WebAPI dokumentáció kibővítése

Írtam már arról, hogy a Microsoft.AspNet.WebApi.HelpPage NuGet csomaggal milyen könnyen generálhatunk dokumentációt a WebAPI-nkhoz. Mint minden készen kapott megoldással, ezzel is akkor kezdődnek a nehézségek, amikor az ember olyasmit szeretne, amire helyből nincs felkészítve. Szerencsére ebben az esetben a teljes forráskód rendelkezésre áll, így viszonylag egyszerűen testreszabhatjuk a működést és a megjelenést.

Példaként tegyük fel, hogy az API-nk úgy épül fel, hogy minden action hiba esetén a hozzá tartozó enum valamelyik elemét adja vissza hibakódnak a hozzá tartozó hibaüzenettel együtt, és a feladat az, hogy ezek a hibakódok megjelenjenek a dokumentációnkban.

Egy saját attribútummal – amit itt ErrorCodeType-nak hívtam, –  könnyen hozzákapcsolhatjuk a hibakódokat tartalmazó enumot (itt MyErrorCodeEnum) az actionhöz:

[ErrorCodeType(typeof(MyErrorCodeEnum))]

Ezt az információt a következő lépésekkel tehetjük bele a dokumentációba:

1. A Models mappába hozzunk létre egy új osztályt, ami majd egy konkrét hibaág leírására lesz alkalmas, hívjuk ezt ErrorCodeDescription-nek:

public class ErrorCodeDescription
{
  public int Code { get; set; }
  public string Message { get; set; }
}

 

2. A HelpPageApiModel.cs fájl írja le azt a view-modellt, ami alapján a dokumentáció oldal megjelenik. Ebbe az osztályba vegyünk fel egy új tulajdonságot, ami az összes hibalehetőséget fogja tartalmazni egy listában:

public List<ErrorCodeDescription> ErrorResponses { get; set; }

 

3. A HelpPageConfigurationExtensions.cs fájlban található az a GenerateApiModel metódus, ami felépíti a HelpPageApiModel típusú apiModel nevű változóban található view-modellt. Itt a meglévőek mintájára készíthetünk egy saját metódust, ami kiolvassa a csatolt attribútumot, és az alapján felépíti az ErrorResponses listát, például így:

private static void GenerateErrorResponses(HelpPageApiModel apiModel)
{
  ErrorCodeTypeAttribute attribute = apiModel.ApiDescription.ActionDescriptor
    .GetCustomAttributes<ErrorCodeTypeAttribute>().FirstOrDefault();
  Type enumType = attribute.ErrorCodeEnumType;
  string[] names = Enum.GetNames(attribute.ErrorCodeEnumType);

  foreach (string name in names)
  {
    apiModel.ErrorResponses.Add(new ErrorCodeDescription
    {
      Code = (int) Enum.Parse(enumType, name),
      Message = "TODO"
    });
  }
}

 

4. A modell kirenderelését a Views/Help/DisplayTemplates/HelpPageApiModel.cshtml nézet végzi. A meglévő kódok mintájára ide felvehetjük az alábbi blokkot, ami az ErrorResponses lista megjelenítését az ErrorResponses partial view-ra bízza:

@if (Model.ErrorResponses.Any()) 
{ 
  <h3>Error Responses</h3> 
  @Html.DisplayFor(m => m.ErrorResponses, "ErrorResponses") 
}

 

5. Természetesen létre kell hoznunk ugyanebben a mappában egy ErrorResponses.cshtml fájlt, ami @model-ként egy List<ErrorCodeDescription> példányt fog kapni, amit utána úgy jelenítünk meg a weboldalon, ahogy csak szeretnénk.

 

Ez elsőre sok lépésnek tűnik, de valójában egészen logikus, érdemes megbarátkozni vele.

 

Technorati-címkék: ,
Kategóriák:Webfejlesztés Címke:

WebAPI dokumentáció generálása több szerelvényből

2014.10.3. 10:09 Hozzászólás

A Microsoft.AspNet.WebApi.HelpPage NuGet csomag segítségével nagyon könnyen generálhatunk egészen barátságos dokumentációt a WebAPI-nkhoz. A megoldás alapja, hogy a WebAPI projekt kommentjeiből a C# fordítót felhasználva XML fájlt készítünk, amit aztán egy MVC controller felolvas, és barátságos HTML oldalakká fordít.

A problémák akkor jönnek, ha a a REST API publikus interfészén olyan típusok találhatóak, amik nem a WebAPI projektben vannak, hanem egy másik DLL-ben, ugyanis a másik DLL – tipikusan library – kommentjeiből generált XML fájl ugyan bekerül az API bin mappájába, de a webdeploy már nem viszi magával, tehát futási időben nem lesz ott a megfelelő helyen.

A probléma két lépésben orvosolható:

  1. A library XML fájljának bele kell kerülnie a webdeploy csomagba.
  2. A controllert át kell írni, hogy több XML fájllal is működjön.

 

A webdeploy csomag kiegészítése

A webdeploy csomag úgy készül, hogy fordítás után összemásolódik az összes fájl egy mappába, majd ennek a mappának a tartalmából áll össze a csomag. Mivel ezt a folyamatot az MSBuild vezérli, kis trükkel újabb fájlt is be tudunk tenni ebbe az ideiglenes mappába. Mindössze a WebAPI projekthez tartozó .csproj fájlt kell kiegészítenünk:

<Target Name="CopyAdditionalFiles">
  <Message Text="Copy additional files..." Importance="high"/>

  <ItemGroup>
    <_CustomFiles Include="$(ProjectDir)bin\MyLib.xml" />
    <FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
      <DestinationRelativePath>bin\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
    </FilesForPackagingFromProject>
  </ItemGroup>
</Target>

<PropertyGroup>
  <CopyAllFilesToSingleFolderForMsdeployDependsOn>
    CopyAdditionalFiles;
    $(CopyAllFilesToSingleFolderForMsdeployDependsOn);
  </CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>

A fenti módosítás Visual Studio 2012-től kezdve működik, a korábbi verziókhoz képest ugyanis átnevezték a CopyAllFilesToSingleFolderForMsdeployDependsOn elemet.

 

Dokumentáció generálása több XML fájlból

A fent említett NuGet csomag egyetlen XML fájlból tud dokumentációt előállítani. Ha azt szeretnénk, hogy több fájllal is megbirkózzon, akkor módosítanunk kell az XmlDocumentationProvider osztály konstruktorát:

public XmlDocumentationProvider(IEnumerable<string> documentPaths)
{
  if (documentPaths == null)
  {
    throw new ArgumentNullException("documentPaths");
  }

  XDocument finalDoc = null;
  foreach (string documentPath in documentPaths)
  {
    if (finalDoc == null)
    {
      finalDoc = XDocument.Load(File.OpenRead(documentPath));
    }
    else
    {
      XDocument additionalDoc = XDocument.Load(File.OpenRead(documentPath));
      finalDoc.Root.XPathSelectElement("/doc/members")
        .Add(additionalDoc.Root.XPathSelectElement("/doc/members").Elements());
    }
  }

  _documentNavigator = finalDoc.CreateNavigator();
}

A módosítás eredményeként a konstruktornak már több fájl útvonalát kell átadni a korábbi egy helyett. Az elsőt ugyanúgy fogja betölteni, mint korábban, a többit pedig utána fogja fűzni a memóriában. A végeredmény egyetlen nagy XML dokumentum, így a NuGet csomag többi részét nem is kell módosítanunk.

Természetesen a HelpPageConfig.cs-ben már tömb paraméterrel kell meghívnunk a konstruktort, például:

string[] documentPaths = 
{
  HttpContext.Current.Server.MapPath("~/bin/MyAPI.xml"),
  HttpContext.Current.Server.MapPath("~/bin/MyLib.xml")
};
config.SetDocumentationProvider(new XmlDocumentationProvider(documentPaths));

 

Technorati-címkék: ,,
Kategóriák:Webfejlesztés Címke:

Kód futtatása tesztelés elején és végén

Aki Visual Studioban írt már unit teszteket, biztosan találkozott a [TestClass] és [TestMethod] attribútumokkal, amelyekkel a teszteket tartalmazó osztályokat és a konkrét teszteket meg tudjuk jelölni. Hasonlóképpen használhatunk attribútumokat olyan kódok jelölésére, amelyeknek a tesztek előtt vagy után kell lefutniuk:

A TestInitialize és TestCleanup attribútumokkal ellátott metódusok minden teszt előtt és után futnak le.

A ClassInitialize és ClassCleanup attribútumokkal ellátott metódusok az osztályban található első teszt futtatása előtt és az utolsó futtatása után futnak le.

Az AssemblyInitialize és AssemblyCleanup attribútumokkal ellátott metódusok a szerelvényben található első teszt futtatása előtt és az utolsó futtatása után futnak le.

Az utóbbiak különösen hasznosak tudnak lenni CI esetén.

 

Technorati-címkék: ,
Kategóriák:Visual Studio 2013 Címke:

Windows 10: Kinek-mit-mikor?

2014.09.30. 17:41 Hozzászólás

A mai nap a Microsoft bejelentette a Windows következő, “Threshold” kódnevű változatának első előzetesét. Az előzetessel (preview) kapcsolatban nagyon fontos megérteni, hogy a cég jelentősen más stratégiát fog követni a végleges változat előtti kiadásokkal, mint korábban. Biztosan sokan emlékeznek még az alfa-béta-RTM időkre, amit azután felváltott a CTP-CTP-RC-RTM sorozat. Az új Windows verzió a mostani tervek szerint több előzetes, azaz preview formájában fog megjelenni, de nem is az elnevezés a lényeg, hanem hogy az egyes előzetesek jól meghatározott célközönségnek fognak szólni.

Ez a mostani az ún. enterprise preview, azaz a nagyvállalati ügyfeleknek szóló előzetes, amit a következő egy év folyamán újabb előzetesek fognak követni, várhatóan ebben a sorrendben és időzítéssel:

windows-threshold-elozetesek

Jelen pillanatban senki sem tudja pontosan megmondani, hogy az egyes verziókban mi lesz benne, csak az biztos, hogy amit a mostani Windows 10 előzetesben látunk, az még sokat fog változni. Bár a mostani előzetesben is találunk leginkább végfelhasználóknak szóló újdonságokat (több desktop, modern alkalmazások ablakban, Start menü, keresés stb.), ezek még jócskán változhatnak, hiszen ennél a kiadásnál nem ezekre koncentráltak a fejlesztők.

Mit érdemes most kipróbálni? Elsősorban a nagyvállalatoknak szóló újdonságokat, de természetesen lehet visszajelzéseket küldeni minden más funkcióval kapcsolatban is, hiszen a fejlesztőcsapat minden feedbacket komolyan vesz. Sok idő van még a végleges verzióig, sok képlékeny rész van, ami majd a visszajelzések alapján fog kialakulni. Csak épp kimondottan sokat nem érdemes olyan dolgokon pörögni, amik nem az adott kiadás fókuszába esnek.

 

Technorati-címkék:
Kategóriák:Windows Címke:

GUID definiálása XSD-ben

2014.09.30. 14:30 Hozzászólás

XML dokumentumokban gyakran előfordul, hogy egy elem vagy attribútum GUID értéket tartalmaz. Mivel egy XML a hozzá tartozó XSD nélkül fabatkát sem ér, nem ritka feladat, hogy XSD-ben elő kellene írnunk, hogy az adott érték csak GUID lehet. Az XSD sokféle beépített típust támogat, de sajnos GUID nincs, így marad a klasszikus regexes megoldás:

<xs:schema ...>

  <xs:simpleType name="guid">
    <xs:restriction base="xs:string">
      <xs:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-
[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" />
    </xs:restriction>
  </xs:simpleType>

Ha ez megvan, akkor pontosan úgy hivatkozhatunk a saját guid típusunkra, mint a beépítettekre:

<xs:attribute name="id" type="guid" use="required" />

Érdemes megfigyelni, hogy a regex elején és végén nincs $ és ^ jel, ugyanis a minta mindig a teljes értékre vonatkozik.

 

Technorati-címkék: ,
Kategóriák:Webfejlesztés Címke:

HTTPS: rendesen vagy sehogy

Volt szerencsém Bolognába látogatni nyáron, és örömmel láttam, hogy a repülőtéren ingyenes wifi szolgáltatás van. Lehet, hogy már ekkor gyanakodnom kellett volna, de igazából akkor kezdett a dolog furcsa lenni, amikor a felkapcsolódás után ez az oldal fogadott a böngészőben:

airport-ssl-warning

A hibaüzenet szerint az oldalhoz tartozó SSL tanúsítvány “kicsit” hibás:

  • Nem megbízható a kiállítója.
  • Lejárt az érvényessége.
  • Másik weboldalra szól.

Valójában csak akkor lehetne hibásabb, ha már vissza is vonták volna a tanúsítványt.

Aki mégis továbblép, az ezzel az oldallal találkozhat a bolognai reptéren:

airport-webpage

Igazán eredeti dizájn. Oké, Bologna nem egy metropolisz, de a helyi egyetemen simán találhattak volna egy unatkozó diákot, aki egy hétvége alatt pofásabb weboldalt tud összedobni.

Ekkor már kíváncsi lettem és kis kísérletezéssel hamar kiderült, hogy a weboldalnak semmi köze ahhoz, hogy működik-e az internet hozzáférés, vagy sem.

Sok már itt a gyanús tényező:

  • Tanúsítvány
  • IP cím
  • Dizájn
  • Telefonszám gyűjtögetés

Ez volt az a pillanat, amikor konkrétan felálltam és körülnéztem, hátha ott ül valahol Troy Hunt az ő Pineapple-jével.

Egy rendes SSL tanúsítvány ezeket a kétségeimet könnyen eloszlathatta volna. De az ilyen, érvénytelen tanúsítvány semmire nem jó, mindössze annyit garantál, hogy az átlagfelhasználót idegesíteni fogja az oldal, a szakértőbb felhasználók pedig aggódni fognak az adataik biztonsága miatt. Aki HTTPS-re adja a fejét, csinálja rendesen, különben csak az ellenkezőjét éri el vele.

 

Technorati-címkék: ,
Kategóriák:Biztonság, Webfejlesztés Címke:

JSON vagy nem JSON, ez itt a kérdés

Amikor egy REST API-hoz készítünk unit tesztet könnyen előfordulhat, hogy meg kell vizsgálnunk, hogy a szervertől kapott válasz olyan formában van-e, mint amiben kértük. Például egy stringről el kell döntenünk, vagy korrekt JSON-t tartalmaz-e.

Sok olyan megoldást lehet találni a neten, ami azt mondja, hogy elég, ha ellenőrizzük, hogy a kapott string < vagy { karakterrel kezdődik-e, hiszen a JavaScript Object Notation mindenképpen objektumokról vagy tömbökről szól. Ezzel a módszerrel nem csak az a baj, hogy egyetlen karakterből aligha tudjuk megmondani, hogy érvényes JSON stringről van-e szó, hanem az is, hogy érvényes lehet az a string is, ami nem tömböt vagy objektumot, hanem csak egy egyszerű értéket tartalmaz. Ami pedig a json.org szerint lehet:

json-value

A fapados karakter vizsgálgatás helyett szükségünk lenne egy korrektebb IsValidJson függvényre. Sajnos ilyet sehol nem találtam készen, de a Newtonsoft JSON.NET könyvtárral sikerült így megoldani a problémát:

try
{
    JToken.Parse(input);
    return true;
}
catch (JsonReaderException)
{
    return false;
}

Van jobb ötlete valakinek?

 

Technorati-címkék: ,,
Kategóriák:Webfejlesztés Címke: , ,
Követem

Értesítést küldünk minden új bejegyzésről a megadott e-mail címre.

Csatlakozz a 78 követőhöz

%d blogger ezt szereti: