Monthly Archives: June 2010

Csiripelő alkalmazás

A Twitter, a Messenger és a vuvuzela számomra egy kategória: mások által érthetetlen okokból imádott zajkeltő eszközök. Most az egyik projektünkben mégis azt kellett megoldanunk, hogy az alkalmazás időnként csiripeljen egyet a Twitteren.

Ennek megvalósítására nagyon sok példát lehet találni a neten, a legtöbb szépséghibája azonban, hogy a kihalásra ítélt basic hitelesítést használja, ami helyett már az OAuth a preferált. Az OAuthnak kétségkívül vannak előnyei, azonban a használata messze nem olyan egyszerű, mint a minden kliens által támogatott basic hitelesítésnek. Nézzük sorban!

Először is persze kell egy Twitter account, ahova az alkalmazás írogatni fog. Ezek után a Settings –> Connections oldalon regisztrálnunk kell a kliens alkalmazást. Nálunk egy webalkalmazásról volt szó, ezért az Application Type: Client, a Default Access Type pedig Read & Write lett. Bár a miénk egy webalkalmazás, azért lett a típusa Client és nem Browser, mert nem akartuk, hogy a felhasználó böngészője ide-oda ugráljon az saját weblapunk és a Twitter között, hanem az volt a cél, hogy a háttérben észrevétlenül kikerüljön egy csirip a Twitterre, ha történik valami a mi webhelyünkön. Fontos, hogy ha az alkalmazás csak posztol a Twitterre, de másra nem használja, akkor a Use Twitter for login opciót ne kapcsoljuk be. Ha ügyesek voltunk, akkor a varázsló végén kapunk egy oldalt a következő paraméterekkel:

  • Consumer key
  • Consumer secret
  • Request token URL
  • Access token URL
  • Authorize URL

Ez mind kell az OAuth-hoz. Sőt, ha egy konkrét alkalmazás a kliens, akkor kell még 2 adat, egy Access token és egy Access token secret, nosza szerezzük meg őket! Látogassunk el a http://dev.twitter.com/apps oldalra (biztos be is van linkelve valahova, csak én nem találtam meg), majd kattintsunk az alkalmazásunk mellett található Edit details linkre, majd a betöltődő oldalon az Application detail, végül pedig a My Access Token linkre. Jegyezzük fel gondosan az oauth_token és oauth_token_secret értékeket.

Megvan tehát mindenünk, irány a Visual Studio, írhatjuk a kódunkat, az sokkal egyszerűbb lesz. Mivel az OAuth protokollt és a teljes Twitter API-t valahogy nem volt kedvem implementálni, némi keresgélés és tesztelés után a választásom a Twitterizerre esett.

Próbaként készítsünk egy konzol alkalmazást, referenciaként adjuk hozzá a Twitterizer2.dll-t és persze kell egy using Twitterizer; sor is.

Az a jó a Twitterizerben, hogy az egész OAuth mizéria számunkra ennyit jelent:

  OAuthTokens tokens = new OAuthTokens()
  {
    ConsumerKey = @"jrnGHJxU...",
    ConsumerSecret = @"c0nsmR...",
    AccessToken = @"aCtKn...",
    AccessTokenSecret = @"scR3t..."
  };

Ezen kívül a központi objektum a TwitterStatus, például a korábbi csiripeket a GetHomeTimeLine függvénnyel kérdezhetjük le:

  TwitterStatusCollection statuses = TwitterStatus.GetHomeTimeline( tokens );
  foreach( TwitterStatus status in statuses )
  {
    Console.WriteLine( status.Text );
  }

Érdemes tudni, hogy az API-t nem lehet a végtelenségig megpörgetni, hanem mint sok más helyen, itt is vannak limitek, amiket így kérdezhetünk le:

  TwitterRateLimitStatus limit = TwitterRateLimitStatus.GetStatus( tokens );

A kapott limit objektum ilyen értékeket tartalmaz:

  {Twitterizer.TwitterRateLimitStatus}
    base {Twitterizer.Core.TwitterObject}: {Twitterizer.TwitterRateLimitStatus}
    HourlyLimit: 175
    RemainingHits: 174
    ResetTime: {2010.06.24. 18:05:52}
    ResetTimeString: "Thu Jun 24 16:05:52 +0000 2010"

Ezt a korlátot figyelembe véve már küldhetjük is az üzenetünket a nagyvilágnak:

  TwitterStatus result = TwitterStatus.Update( tokens, "Működik!" );

A kapott TwitterStatus objektum tulajdonságaiból sok minden kiderül, talán a legfontosabb a poszt egyedi azonosítója (Id), illetve hogy belefértünk-e a 140 karakterbe (IsTruncated).

Jó csiripelést!

 

Technorati-címkék: ,,

SharePoint 2010 BDC adatbázis neve

A SharePoint 2007 idején már szörnyülködtem egy kicsit azon, hogy milyen barátságtalan nevet kapnak az adatbázisok az odacsapott GUID-dal a végén. A rossz hír az, hogy ez a tünet megvan SharePoint 2010 esetén is, ráadásul több adatbázisunk is van.

A korábbi cikkben megírtam, hogyan adhatunk GUID-mentes nevet az AdminContent adatbázisnak a psconfig használatával parancssorból. A 2007-es parancs nagyjából működik 2010 alatt is, csak még egy –passphrase kapcsolót kell a végére írni.

Az új verzióban azonban születik még egy Business Connectivity Services (leánykori nevén Business Data Catalog) adatbázis is, természetesen az is megjegyezhetetlen névvel. Ha ezt a gyereket is mi szeretnénk elnevezni, irány a PowerShell:

  $serviceUserName = "MYDOMAINMyServiceAccount"
  $servicePassword = "MySecurePassword"

  $password = ConvertTo-SecureString $servicePassword -asPlainText -force

  $credential = New-Object System.Management.Automation.PSCredential 
$serviceUserName, $password $managedAccount = New-SPManagedAccount -credential $credential $appPool = New-SPServiceApplicationPool "SharePoint Services"
-account $managedAccount New-SPBusinessDataCatalogServiceApplication
-applicationpool $appPool
-name "Business Connectivity Services"
-DatabaseName "SharePoint_BDC"

Technorati-címkék: ,,

Calling GetProcAddress on ISAPI filter “aspnet_isapi” failed

Épp egy ASP.NET 4-es alkalmazást próbáltunk IIS 7-en működésre bírni, amikor szembetaláltuk magunkat az alábbi sárga halállal:

HTTP Error 500.0 – Internal Server Error
Description: Calling GetProcAddress on ISAPI filter "C:WindowsMicrosoft.NETFrameworkv4.0.30319aspnet_isapi.dll" failed.
Error Code: 0x8007007f

Mindez egy olyan Windows 7-es gépen, amire nemrég került fel a Visual Studio 2010 és az IIS 7 is. A hibaüzenet szerencsére ad támpontokat a megoldásra, ennek megfelelően ellenőriztük a hiányzó függőségeket, NTFS jogosultságokat, config fájlokat. Sőt, próbálkoztunk aspnet_regiis /i-vel is, hátha a telepítési sorrend volt rossz, de nem segített 😦 A legszebb az egészben az volt, hogy egy VS 2010-ben újonnan létrehozott alkalmazás is ugyanilyen tüneteket produkált.

Végül megnyitottuk IIS Managerben a webszerver ISAPI Filters modulját és rögtön fény derült a hiba okára:

aspnet_isapi error

Valamilyen érthetetlen okból bekerült az aspnet_isapi.dll az ISAPI filterek közé. Csakhogy ez nem filter, hanem extension, nem véletlenül anyázott érte az IIS!

Egy gyors Remove és minden megoldódott.

 

Technorati-címkék: ,,,

URL rövidítés kódból 2 – Bit.ly

Legutóbb bemutattam, milyen egyszerű a TinyURL-t REST-es API-ja segítségével beépíteni saját alkalmazásunkba. Nem a TinyURL az egyetlen ilyen szolgáltatás, léteznek mások is az interneten. A Bit.ly például statisztikát is ad a rövidített URL-ek használatáról, cserébe természetesen regisztrálnunk kell.

A regisztráció után kaphatunk egy API key-t, a felhasználónevünket és ezt a kulcsot kell beépítenünk a kódunkba, ha az API-n keresztül akarjuk elérni a szolgáltatást. A jelszót nem kell bedrótoznunk.

Az URL rövidítéshez egy REST-es hívást kell küldenünk az alábbi címre, a helyőrzők helyére értelemszerűen behelyettesítve a hosszú URL-t, a belépési nevünket és a kapott API kulcsot:

  const string SERVICEFORMAT = 
"http://api.bit.ly/v3/shorten?format=xml&longUrl={0}&login={1}&apiKey={2}&version=3.0";

A szervertől kapott válasz formátuma a következő:

  HTTP/1.1 200 OK
  Server: nginx/0.7.42
  Date: Sun, 13 Jun 2010 04:03:32 GMT
  Content-Type: application/xml; charset=UTF-8
  Connection: keep-alive
  MIME-Version: 1.0
  Content-Length: 344

  <?xml version="1.0" encoding="UTF-8"?>
  <response>
    <status_code>200</status_code>
    <status_txt>OK</status_txt>
    <data>
        <url>http://bit.ly/crT0M6</url>
        <hash>crT0M6</hash>
        <global_hash>bwJlya</global_hash>
        <long_url>http://www.msdnkk.hu</long_url>
        <new_hash>0</new_hash>
    </data>
  </response>

Ami ebből érdekes számunka, az a status_code és az url mezők, az utóbbit csak a status mezők ellenőrzése után szabad figyelembe venni. Csinálhatunk a válaszhoz egy burkoló osztályt:

  class BitlyResult
  {
    public string StatusCode { get; set; }
    public string StatusText { get; set; }
    public string ShortUrl { get; set; }
    public bool IsValid
    {
      get
      {
        return this.StatusCode.Equals( "200", StringComparison.OrdinalIgnoreCase ) && 
this.StatusText.Equals( "OK", StringComparison.OrdinalIgnoreCase ); } } }

Az egész szolgáltatáshívást pedig az alábbi metódusba csomagolhatjuk be:

  static string Shorten( string longUrl, string login, string apiKey )
  {
    string serviceUrl = String.Format( CultureInfo.InvariantCulture, 
SERVICEFORMAT,
HttpUtility.UrlEncode( longUrl ), login, apiKey ); XDocument response = XDocument.Load( serviceUrl ); BitlyResult result = ( from r in response.Descendants( "response" ) select new BitlyResult { StatusCode = r.Element( "status_code" ).Value, StatusText = r.Element( "status_txt" ).Value, ShortUrl = r.Element( "data" ).Element( "url" ).Value }
).Single(); return result.IsValid ? result.ShortUrl : longUrl; }

Nem annyira Einsteines, mint a TinyURL, de cserébe kapunk sok plusz statisztikai információt a rövidített címek használatáról.

 

Technorati-címkék: ,,

AppFabric és az ASP.NET 4

Múlt héten végre megjelent a Windows Server AppFabric végleges változata, ami több szempontból is érdekes:

  • Nem webes alkalmazások számára azért, mert a Windows Communication Foundation és a Windows Workflow Foundation alkalmazásához nyújt támogatást.
  • Webes alkalmazások számára pedig azért, mert végre elérhetővé vált a korábban Velocity kódnéven futó elosztott gyorsítótár. Pontosabban:
  • A Windows Server AppFabric Cache egy explicit, elosztott, egységes, memóriabeli adat gyorsítótár.

Aki még nincs képben, annak feltétlenül ajánlom Bátyai Krisztián két bevezető cikkét:

Sajnos a dokumentáció egyelőre meglehetősen lájtos, ezért is érdekes, hogy az ASP.NET csapat nemrég kitett a CodePlexre mintakódokat, amelyek bemutatják a Velocity használatát output cache és session state providerként.

Technorati-címkék: ,,,

URL rövidítés kódból 1 – TinyURL

Az egyik projektünkben string hossz limitek között vergődve arra jutottunk, hogy a felhasználó által megadott URL-ek rövidítésével nyerünk pár karakternyi helyet. Nosza meg is néztük a TinyURL URL rövidítő szolgáltatást és szembetaláltuk magunkat a világ legegyszerűbb API-jával.

Na, vajon milyen technológiát választ egy olyan cég, aki a webes szolgáltatását tényleg minden fajta kliens számára biztosítani szeretné? Manapság természetesen REST-et.

És vajon hogy néz ki a legegyszerűbb REST interfész egy string bemenettel és egy string kimenettel? Így:

http://tinyurl.com/api-create.php?url=http://www.msdnkk.hu

A legszebb az egészben, hogy a válasz minden körítés nélkül mindössze ennyi:

HTTP/1.1 200 OK
X-Powered-By: PHP/5.3.2
Content-type: text/plain
Connection: close
Date: Tue, 08 Jun 2010 04:40:16 GMT
Server: TinyURL/1.6
Content-Length: 23

http://tinyurl.com/36q7yh8

Mindez .NET-ből némi prefixeléssel és URL kódolással:

  internal static class TinyUrlService
  {
    const string SERVICEFORMAT = @"http://tinyurl.com/api-create.php?url={0}";

    internal static string Shorten( string longUrl )
    {
        if( !longUrl.StartsWith( "http://", StringComparison.OrdinalIgnoreCase ) )
        {
            longUrl = "http://" + longUrl;
        }

        string serviceUrl = String.Format( CultureInfo.InvariantCulture, SERVICEFORMAT, HttpUtility.UrlEncode( longUrl ) );

        return new WebClient().DownloadString( serviceUrl );
    }
  }

Erre mondta Einstein, hogy “Mindent a lehető legegyszerűbben kell csinálni, de egy fokkal sem egyszerűbben.”

 

Technorati-címkék: ,,

Windows 7 Jump List – amire nem jó

Az elmúlt órákat azzal töltöttem, hogy megpróbáltam a Windows 7 Jump List funkcióját beépíteni a saját alkalmazásomba. Közben számtalanszor volt “na neee, ezt nem hiszem el :(” élményem, ami után mindig hosszas guglizás következett, ezért leírom a tapasztalatokat és a tanulságokat, hogy másnak megspóroljak egy kis időt:

1. A jump list jól programozható WPF 4-ből a System.Windows.Shell névtéren keresztül, XAML-ből és code behindból egyaránt, nem kell hozzá a Windows API Code Pack. “Természetesen” a két környezetben nem azonos az API, tehát nem mindegy, milyen cikket olvas az ember.

2. A jump list Recent items kategóriája csak akkor használható, ha az alkalmazáshoz van fájl kiterjesztés társítva, egyébként nem. Itt jól jöhet a RegistrationHelper.RegisterFileAssociations metódus a Windows API Code Pack példák közül vagy persze írhatunk telepítőt is.

3. A jump listben lehet saját taskokat létrehozni, ennek bemutatására érdekes módon az összes demó a Notepad.exe-t és a Calc.exe-t indítja el. Nem véletlenül. Itt csak olyan útvonalakat lehet megadni, mint amiket például a Start menü Run ablakába be lehet írni, ami a shell által elindítható, végrehajtható. Ha a fájl nem létezik a diszken, kivételt kapunk. Nem véletlenül hívják ezt belül shell linknek, csak managed környezetben lett “task” a neve.

4. A jump list nem egyenlő a menüvel, az ide felvett taskokra történő kattintásról nem fog értesülni az aktuális alkalmazás. Valami hihetetlen kreativitásról tett tanúságot az, aki kitalálta, hogy ha egy jump list elemre kattintunk, akkor mindig el fog indulni egy új példány az alkalmazásból. Annyit tudunk tenni, hogy megadjuk, hogy ez az újabb példány milyen parancssori paramétereket kapjon meg. Ugye ez épp az a scenario, amire az Explorer, az Internet Explorert és a Wordöt használjuk, arra kiváló.

5. Ha olyan taskot szeretnénk a jump listbe tenni, ami az alkalmazás aktuális példányára vonatkozik (például ablak maximalizálás, About ablak megnyitása stb.), akkor az egyetlen lehetőség, hogy a saját exe fájlunk útvonalát adjuk meg és parancssori paraméterben tudatjuk, hogy mit szeretnénk tenni vele. Sajnos ebben az esetben is el fog indítani a Windows egy új példányt az alkalmazásból, aminek indulásakor megvizsgálhatjuk, hogy fut-e már másik példány belőle (az eredeti) és annak valahogy (remoting, named pipe, window message stb.) átküldjük, hogy mit kellene éppen csinálnia, majd a második példány bezárja magát. Ennek persze van 2 nagyon fájó hátránya: az alkalmazásunk csak 1 példányban fog tudni futni, az üzenet átküldése pedig elég gusztustalan munka.

Tudtok jobb megoldást?

 

Egyperces: ResolveUrl Page nélkül

Nem ritkán előforduló feladat, hogy egy relatív URL-ből abszolút URL-t kell előállítanunk, vagy egyszerűen csak fel kell oldanunk a tildét. Erre kiváló a ResolveUrl metódus, ami a Control osztály és így a Page része. De mi van akkor, ha még egy egészen kicsit Page példányunk sincsen, mert például egy HttpModule-ban vagyunk?

Érdemes megismerkedni a VirtualPathUtility osztállyal, van egy rakás hasznos metódusa:

  • URL részek lekérdezése: GetDirectory, GetFileName, GetExtension.
  • Záró per-jel kezelése: AppendTrailingSlash, RemoveTrailingSlash.
  • URL típusának lekérdezése: IsAbsolute, IsAppRelative.
  • URL átalakítás: MakeRelative, ToAbsolute, ToAppRelative.

Így már nem is olyan nehéz megoldani a fenti feladatot:

  Uri absoluteUri = new Uri( HttpContext.Current.Request.Url, 
VirtualPathUtility.ToAbsolute( relativeUrl ) );

Azt azonban érdemes tudni, hogy a VirtualPathUtility nem tud query string paramétereket kezelni. Ha arra is szükség van, akkor érdemes körülnézni Michael Palermo és Rick Strahl blogbejegyzései és a hozzá kapcsolódó kommentek között.

Technorati-címkék: