Archívum

Archive for the ‘Webfejlesztés’ Category

Ajaxos fájl feltöltés

Időnként felmerül, hogy jó lenne úgy feltölteni egy fájlt, hogy közben az oldal többi része nem változik, magyarul Ajaxosan. Rossz hírem van, az XMLHttpRequest objektum Level 1 változata ezt nem tudja, tehát ha régebbi böngészőkre is tekintettel kell lennünk, akkor nincs mese trükközni kell.

A legelterjedtebb trükközési módszer az iframe alkalmazása, azt ugyanis bátran lehet postbackelni, az egyetlen szépséghiba, hogy a válasz, például validációs hibák is az iframe-be fognak megérkezni. Tehát ha rejtett iframe-mel dolgozunk, akkor a választ onnan ki kell venni, és az oldal megfelelő részén meg kell jeleníteni. Van tehát feladat bőven, szerencsére a jQuery Form Plugin sokat tud segíteni a megvalósításban.

Először is készítsünk egy view-modelt szerver oldalon, amiben egy HttpPostedFileBase típusú tulajdonság fogja képviselni a feltöltött fájlt. Mellécsaptam még egy kötelező Name tulajdonságot, csak úgy a demonstráció kedvéért:

public class UploadVM
{
    [Required( ErrorMessage = "Please enter a name!" )]
    public string Name { get; set; }

    [Attachment]
    public HttpPostedFileBase Attachment { get; set; }
}

Az [Attachment] a korábbi cikkben bemutatott, fájl validálásra használt attribútum. Ellenőrzi, hogy van-e feltöltve fájl, illetve hogy helyes a kiterjesztése és nem túl nagy-e a mérete.

Ehhez a modellhez már készíthetünk egy űrlapot, ami fel fogja küldeni a fájlt és a megadott nevet:

@using( Html.BeginForm( "Index", "Home", FormMethod.Post, 
        new { id = "myForm", enctype = "multipart/form-data" } ) )
{
    <p>
        <label for="txtName">Name:</label>
        <input type="text" id="txtName" name="Name" />
    </p>

    <p>
        <label for="fupAttachment">File:</label>
        <input type="file" id="fupAttachment" name="Attachment" />
    </p>

    <p>
        <input type="submit" value="Upload" />
    </p>    

    <div id="errors"></div>
}

Fontos, hogy a generált formnak multipart/form-data értékű enctype attribútuma legyen, mert azzal tud csak fájl utazni, illetve létrehoztam még egy errors azonosítójú div-et is, ahol majd a hibaüzeneteket fogjuk megjeleníteni.

Ez az űrlap a HomeController Index nevű actionjére lő, amit így implementálhatunk:

[HttpPost]
public ActionResult Index( UploadVM model )
{
  if( !this.ModelState.IsValid )
  {
    string firstError = ModelState.First( m => m.Value.Errors.Any() )
                                  .Value.Errors[ 0 ].ErrorMessage;
    return this.FileUploadFailure( firstError );
  }

  // Process the file here

  string message = String.Format( "The file '{0}' is successfully uploaded.", 
                                  model.Name );
  return this.FileUploadSuccess( message );
}

Ha a view-model valamelyik tulajdonsága hibás, akkor az attribútumoknak köszönhetően a hibák bekerülnek a ModelStatebe, amit a metódus elején szokás szerint ellenőrzünk. Ha van hiba, akkor az első hibaüzenettel térünk vissza, ha nincs, akkor pedig feldolgozzuk a fájlt és egy siker üzenettel térünk vissza.

A visszatérési érték egy JSON objektum, mert ezt tudjuk kliens oldalon barátságosan feldolgozni. Csakhogy ne feledjük, hogy a válasz egy iframe-be fog beíródni, és nem minden böngésző szeret iframe-be application/json típusú tartalmat kapni. Szerencsére a jQuery Form Plugin támogatja azt a trükköt, hogy a JSON tartalmat egy <textarea> elembe ágyazva küldjük vissza a szerverre text/html típusú válaszként, onnan ő majd kiveszi a JSON tartalmat.

Hogy ez a csomagolás egyszerű legyen, készítettem egy saját result típust:

public class FileUploadJsonResult : JsonResult
{
  public override void ExecuteResult( ControllerContext context )
  {
    this.ContentType = "text/html";
    context.HttpContext.Response.Write( "<textarea>" );
    base.ExecuteResult( context );
    context.HttpContext.Response.Write( "</textarea>" );
  }
}

Az egyszerű példányosításhoz pedig két bővítő metódust, melyek közül az egyikkel sikert, a másikkal hibát lehet jelezni:

public static FileUploadJsonResult FileUploadSuccess( 
  this Controller controller, string successMessage = null )
{
  return new FileUploadJsonResult
  {
    Data = new { Success = true, Message = successMessage }
  };
}

public static FileUploadJsonResult FileUploadFailure( 
  this Controller controller, string errorMessage )
{
  return new FileUploadJsonResult
  {
    Data = new { Success = false, Message = errorMessage }
  };
}

Itt a Data tulajdonságban bármilyen szerkezetű objektumot összerakhatunk, az fog megérkezni válaszként a kliensre JSON formátumban. Itt most az egyszerűség kedvéért egy Success tulajdonságban jelzem, hogy a feltöltés hibátlanul megtörtént-e, és egy Message tulajdonságban hibaüzenetet vagy sikeres feltöltésre utaló üzenetet küldök vissza, amit a böngésző megjeleníthet.

Készen vagyunk tehát a szerver oldallal: van egy formunk, ami elPOSTolható egy actionnek, ami validálja a feltöltött tartalmat, és ha minden mező érvényes adatot tartalmaz, akkor feldolgozza őket, és az eredményt JSON válaszban jelzi.

Már csak a kliens oldal van hátra, amit természetesen a jQuery Form Plugin segítségével valósítunk meg. Ahogy a neve is mutatja, ez egy jQuery plugin, amit a form elemet burkoló jQuery objektumra (itt épp $form) kell ráhúznunk:

$form.ajaxForm({
    iframe: true,
    dataType: "json",
    beforeSubmit: function () {
      // TODO     },
    success: function (result) {
      // TODO 
    },
    error: function () {
      // TODO 
    }
});

Az alábbi eseménykezelőket célszerű megvalósítanunk:

  • beforeSubmit: ez a POST elküldése előtt fut le, itt írhatjuk ki például, hogy a feltöltés folyamatban van, vagy például a jQuery BlockUI plugin segítségével letilthatjuk az űrlapon lévő vezérlőket.
  • success: ez akkor hívódik meg, ha látszólag hibátlan volt a feltöltés, bár tapasztalatom szerint akkor is meg tud hívódni, ha a szerver valamilyen hibát jelez. Ha nem volt hiba, akkor a paraméterül kapott változóban a szerverről visszaküldött JSON objektum jelenik meg, de számítsunk rá, hogy hiba esetén ez lehet undefined is!
  • error: hiba esetén ez fut le.

Íme egy példa a success callback implementálására:

if (!result) {
$errors.html('<div class="validation-summary-errors"><ul><li>Oooops....
                </li></ul></div>');
}
else {
  $form.resetForm();

  if (result.Success === true) {
    var message = result.Message;
    if (message && message.length > 0) {
      $errors.html( message );
    }
  }
  else {
    $errors.html('<div class="validation-summary-errors"><ul><li>{0}
                  </li></ul></div>'.format(result.Message));
  }
}

Ebben a kódban a hibák megjelenítését egy kicsit összetett HTML darabkával végezzük. Ennek az a jelentősége, hogy a klasszikus ASP.NET MVC-s validálás is pont ilyen HTML-t generál magából, tehát a mi Ajaxos hibáink is pont ugyanolyan stílussal fognak megjelenni.

A format egy a szerver oldali String.Formathoz hasonló függvény, amit például így implementálhatunk JavaScriptben:

String.prototype.format = function () {
  var args = arguments;
  return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) {
    if (m === "{{") { return "{"; }
    if (m === "}}") { return "}"; }
    return args[n];
  });
};

Ha a szerverről nem csak az első, hanem összes ModelState hibát visszaadnánk, akkor egy ciklusban renderelhetnénk ki őket.

A cikkhez tartozó forráskód rengeteg kommenttel letölthető innen: http://sdrv.ms/10QQLSp

 

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

Feltöltött fájl validálása ASP.NET MVC-ben

Az ASP.NET MVC egyik szépségét a kód tisztasága adja, ami részben a model validálásnak köszönhető. Az ember fogja a System.ComponentModel.DataAnnotations névtérben lévő attribútumokat, teleaggatja velük a modellt vagy a view-modelt, és máris működik a validálás, ráadásul a kód egyéb részeit sem zavarja össze.

Mindez szép és jó, ha egy string értékét vagy hasonlóan egyszerű inputot szeretnénk vizsgálni, de például egy feltöltött fájl ellenőrzésére nem sok lehetőségünk van. .NET 4.5-től kezdve ugyan már van FileExtensionAttribute, de gyakran ennél többre van szükségünk.

Amire szinte mindig szükség van:

  • Töltött-e fel fájlt a felhasználó?
  • A feltöltött fájl kiterjesztése megfelel-e?
  • A feltöltött fájl mérete a meghatározott maximumon belül van-e?

De lehet néhány extrább igény is:

Készítsünk magunknak saját attribútumot! Arra kell csak figyelnünk, hogy a ValidationAttribute ősosztályból származzon, és hogy a feltöltésnél használatos HttpPostedFileBase típusú változókat validáljuk vele.

Íme egy megoldás:

[AttributeUsage( AttributeTargets.Property )]
public sealed class AttachmentAttribute : ValidationAttribute
{
  protected override ValidationResult IsValid( object value, 
ValidationContext validationContext ) { HttpPostedFileBase file = value as HttpPostedFileBase; // A fájl kötelező. if( file == null ) { return new ValidationResult( "Tölts fel fájlt!" ); } // A fájl max. 10MB-os lehet. if( file.ContentLength > 10 * 1024 * 1024 ) { return new ValidationResult( "A fájl túl nagy!" ); } // A fájl csak PDF lehet. string ext = Path.GetExtension( file.FileName ); if( String.IsNullOrEmpty( ext ) || !ext.Equals( ".pdf", StringComparison.OrdinalIgnoreCase ) ) { return new ValidationResult( "A fájl nem PDF!" ); } // Minden rendben. return ValidationResult.Success; } }

Ha ezzel megvagyunk, akkor már csak rá kell aggatnunk az [Attachment] attribútumot a modell megfelelő tulajdonságára, és a hibák máris be fognak kerülni a ModelState-be.

Ha a webalkalmazásunkban több helyen, többféle fájlt is fel lehet tölteni, akkor bevezethetünk rájuk egy enumot, amit átadunk az AttachmentAttribute konstruktorának. Így minden fájl ellenőrzése egy helyen, központosítva történhet.

 

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

UX tippek és olvasnivalók

Mióta nagyobb arányban használok kisebb kijelzős és érintőképernyős eszközöket, gyakrabban villan belém a felismerés, hogy a user experience, és a felhasználói felületek valóban barátságos, használható formára tervezése mennyire fontos – lenne. Sajnos azt tapasztalom, hogy számos olyan szoftver van, ahol az ötlet kiváló, de a felhasználói felület teljesen elrontja az élményt, és megy az alkalmazás vagy a website a süllyesztőbe.

Sokakkal beszélgetve arra jutottam, hogy ennek egyik oka természetesen a projektek költségérzékenysége (lásd még unit testelés), a másik, hogy egyszerűen nincs UX designer a fejlesztőcsapatokban. (Ez a két dolog persze összefügg, de nem csak a pénz miatt nincs ilyen szakember a projektekben.) Egyik sem fog egyik napról a másikra megváltozni, így nincs más lehetőség, mint saját erőből megoldani és erre két megoldást látok:

  1. Másolás. Az ötletek másolását általában rossz szemmel nézzük, de a felhasználói élmény terén szerintem ez nem egészen van így. Sőt, ha egy megoldás beválik, elterjed és az ismertsége még jobban megkönnyíti a használhatóságát. Persze az is lehet, hogy nem válik be, vagy még nem bizonyított, de kényszerből elterjed és ezért lesz közismert. Ezt a mintát követik a standardek és az ajánlások. Például az érintőkijelzős eszközöknél a “behúzom az ujjam a széléről” gesztus egyáltalán nem logikus, csak azért próbálkozunk vele, mert arra többnyire történni szokott valami.
  2. A meglévő szakembereink kiokosítása. Na, ez sem zökkenőmentes, mert nem minden programozót lehet rávenni arra, hogy a GUI-val foglalkozzon, de szerencsére akadnak olyanok, akiknek igenis van érzékük hozzá. Őket már csak idővel és forrásokkal kell ellátni. Ambrose Little (az ő nevével a korábbi bejegyzésben említett Infragistics Indigo Studio kapcsán találkozhattunk) blogjában például találhatunk egy UX Book List cikket, ami jó kiindulás lehet.

És ha már kiindulás, íme Ambrose UX for Devs Manifestoja:

  1. A tervezést kezdd az ember irányából.
  2. Hagyj időt a kutatásra.
  3. Ne írj, rajzolj.
  4. Próbálj ki sok variációt, majd egyesítsd a hasznos részleteket.
  5. Tesztelj a felhasználókkal.
  6. Csak akkor kódolj, ha nincs más mód.
  7. Végül ügyelj a részletekre is.

Ti mit gondoltok?

 

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

Content Injector for ASP.NET MVC

Aki készített már újrafelhasználható elemeket ASP.NET MVC-ben, bizonyára találkozott már azzal a problémával, hogy egy partial view vagy egy HTML helper működéséhez szükséges egy CSS stíluslap vagy egy külső JavaScript fájl. Ha odafigyelünk a kódunk minőségére, akkor a CSS-t mindig az oldal tetején, a szkriptet pedig mindig az oldal alján töltjük be, gondosan ügyelve arra, hogy ezek a külső erőforrások akkor is csak egyszer töltődjenek be az oldalra, ha több helyen is szükség van rájuk. Viszont ezt csöppet sem egyszerű megoldani, hiszen a partial view-k és a HTML helperek teljesen önállóan, egymástól függetlenül renderelődnek. Bár a probléma egyáltalán nem újkeletű, még ASP.NET WebFormsban sem egyszerű megoldani, MVC-ben viszont kifejezetten nehéz.

Talán nem is meglepő, hogy a készre sütött megoldást Peter Blum tálalja nekünk a Content Injector for ASP.NET MVC formájában. Az öreg motoros ASP.NET fejlesztők már sokszor találkozhattak Peter nevével, aki egyszemélyes cégében leginkább ASP.NET web controlokat készít. Ezek közül a legismertebb a Peter’s Data Entry Suite, amely több, mint 100 WebForms vezérlőt tartalmaz, melyek elsősorban az adatbevitelt és a validációt teszik egyszerűbbé. Igen hasznos csomagról van szó, nem véletlenül kapott már értük számos pozitív értékelést.

Így csöppet sem csodálkoztam, amikor pár héttel ezelőtt Peter bukkant fel egy ötlettel az ASPInsiders listán, ami nagyon kényelmesen megoldja a fenti problémát. Sokan kipróbáltuk, kapott is pár visszajelzést, amit villámgyorsan át is vezetett a kódon, így most már bátran merem ajánlani a Content Injector for ASP.NET MVC projektet, leginkább NuGet csomag formájában.

A használata pofonegyszerű. Először is jelöljük meg az oldalunkon, tipikusan a Layout.cshtml fájlban, azokat a helyeket, ahova majd beszúródnak a tartalmak:

@Injector.InjectionPoint("ScriptFiles")

Ezek után ha például egy view-nak szüksége van a jQuery Validate szkript fájljaira, akkor a view-ból szúrjuk be őket a korábban megjelölt helyekre:

@Injector.ScriptFile("~/Scripts/jquery.validate.min.js");
@Injector.ScriptFile("~/Scripts/jquery.validate.unobtrusive.min.js");

Ez persze csak a legegyszerűbb használati eset, meg lehet adni még további paramétereket (például sorrend), valamint beszúrhatunk stíluslapot, szkriptet, meta tag-et, rejtett mezőt, szkript blokkot, vagy bármi mást, hiszen a rendszer jól kiterjeszthető és konfigurálható (például tracing). Minderről elég részletesen tájékoztat a 23 oldalas User’s Guide.

További érdekesség, hogy a visszajelzések alapján Peter összekapcsolta a Content Injectort a Microsoft Web Optimization Frameworkkel, így a ContentInjector.WOF NuGet csomag telepítése után már StyleBundle is ScriptBundle is beszúrható.

Letöltések:

 

Technorati-címkék: ,,

Optimista konkurenciakezelés ASP.NET MVC-ben

Webes rendszerek esetén nem ritka, hogy ugyanahhoz az adathoz egyszerre több felhasználó fér hozzá és egyszerre módosítják azt. Ha nem teszünk semmit ellene, akkor a későbbi módosítás felülírja a korábbi módosítást, ami az esetek nagy részében nem egyezik a kívánatos eredménnyel. Alapvetően a következő lehetőségeink vannak:

  • Optimista konkurenciakezelés: nem zároljuk az adatot, mert bízunk abban, hogy nem lesz ütközés. Ha mégis előfordul, hogy két felhasználó egyszerre ugyanazt az adatot módosítja, akkor a második módosítás adatbázisba írása előtt figyelmeztetjük a felhasználót, hogy már elavult adatot módosít.
  • Pesszimista konkurenciakezelés: arra számítunk, hogy több felhasználó ugyanazt az adatot akarja módosítani, ezért amint az egyik felhasználó hozzáfér az adathoz zároljuk azt, és addig nem engedünk másik felhasználót hozzá, amíg az első módosítás be nem fejeződik.

Az optimista megoldás hátránya, hogy a felhasználó tipikusan későn értesül arról, hogy feleslegesen dolgozott, mégis sok adat és kevés felhasználó (például admin oldalak) esetén ez a célszerűbb megoldás, ugyanis nem kell zárakkal és azok feloldásával (pl. timeout) vesződnünk.

Az optimista megoldáshoz először is egy olyan mezőre van szükségünk az adatbázisban, ami a rekord módosításakor mindig frissül, azaz egy verzió vagy időbélyeg típusú mezőre. SQL Server esetén pont erre szolgál a timestamp típus, aminek a frissítéséről az SQL Server automatikusan gondoskodik. Tehát csak létre kell hoznunk az oszlopot, a többi megy magától:

VersionNumber timestamp NOT NULL

ORM használata esetén a modell frissítése után a VersionNumbernek byte[] típusú oszlopként kell megjelennie.

Ha egységesen akarunk eljárni és minden olyan táblában, ahol szükség van konkurenciakezelésre ugyanígy nevezzük az oszlopot, akkor célszerű kitalálnunk egy módszert, amivel hivatkozhatunk a “verziózott” táblákra. Ehhez készíthetünk öröklést az ORM modellben, vagy ha a Studio által generált modellt nem akarjuk bántani, akkor interfészt is bevezethetünk:

public interface IVersionedEntity
{
    byte[] VersionNumber { get; set; }
}

Az interfészt a partial osztályoknak köszönhetően külön fájlban alkalmazhatjuk a modellben lévő entitásokra, nem kell belenyúlni a modellbe. Például ha a modellünkben van egy Partner nevű osztály, akkor így “származtathatjuk” az interfészünkből:

public partial class Partner : IVersionedEntity
{
}

Ezzel készen vagyunk az adatbázissal és az adatelérési réteggel.

Következő lépésként fogjuk meg a dolgot a másik végéről, induljunk el a GUI irányából és okosítsuk fel a ViewModelt. Itt a módosítással kapcsolatos VM-ekbe kell tennünk egy VersionNumber tulajdonságot, amit a módosítás előtt feltöltünk az adatbázisból, és az update előtt összevetünk az adatbázisban tárolt értékkel. Itt is választhatjuk az interfészes megoldást, de ha spórolni akarunk a kóddal, akkor alkothatunk ősosztályt is:

public class VersionedObject
{
    [HiddenInput( DisplayValue = false )]
    public byte[] VersionNumber { get; set; }

    public string VersionNumberEncoded
    {
        get
        {
            return Convert.ToBase64String( this.VersionNumber );
        }
    }

}

A VersionNumberEncoded akkor lesz hasznos, ha az értéket például query stringben kell átadnunk, mert egyébként az MVC automatikusan gondoskodik a byte[] típusú érték Base64 kódolásáról, mielőtt a HiddenInput attribútum szerint kiírja egy rejtett mezőbe.

Ezek után a szerkesztéssel kapcsolatos viewmodeleket egyszerűen származtassuk ebből az ősosztályból:

public class EditPartnerVM : VersionedObject
{
    [HiddenInput(DisplayValue = false)]
    public int ID { get; set; }

    public string DisplayName { get; set; }
}

A modellbe így bekerült értékünket ne felejtsük el megutaztatni a kliensre:

@Html.EditorFor( m => m.VersionNumber )

Miután a böngészőből visszajön az adat, a mentés előtt össze kell vetnünk az adatbázisban lévő értékkel. Ehhez készíthetünk például egy CheckConcurrency( VersionedObject viewModel, IVersionedEntity entity ) függvényt, amely összehasonlítja a két paraméter VersionNumber tulajdonságát, és eltérés esetén kivételt dob. Én készítettem egy saját ObjectMissingException osztályt, amit akkor használok, ha az adatbázis rekord null (azaz már törölték a rekordot), és egy ObjectChangedException osztályt, amit akkor, ha a két verziószám eltér egymástól.

Természetesen a felhasználóval valahogy illik tudatnunk, hogy a művelet kudarcba fulladt. Ezt tehetjük például egy saját exception filterrel, ami ezeknél a kivételeknél egy hibaüzenetet tartalmazó view-t jelenít meg:

[AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, 
Inherited =
true, AllowMultiple = false )] public sealed class HandleConcurrencyErrorAttribute :
FilterAttribute, IExceptionFilter { public void OnException( ExceptionContext filterContext ) { if( filterContext.Exception.GetType() == typeof( ObjectChangedException ) ) { filterContext.ExceptionHandled = true; filterContext.Result = new ViewResult { ViewName = "_ObjectChanged" }; } if( filterContext.Exception.GetType() == typeof( ObjectMissingException ) ) { filterContext.ExceptionHandled = true; filterContext.Result = new ViewResult { ViewName = "_ObjectMissing" }; } } }

Legvégül ne felejtsük el ráaggatni ezt a filtert azokra az actionökre, amik a módosítás POST-ját kezelik, hogy a kivétel biztosan ne szálljon egészen a felhasználóig:

[HttpPost]
[HandleConcurrencyError]
public virtual ActionResult EditPartner( EditPartnerVM model )
{ ...

Ha kevés paraméterünk van (például Ajaxos hívások esetén), ne felejtsük el átadni a VersionNumberEncoded értékét az actionnek.

Ti hogyan oldjátok meg ezt a problémát?

 

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

50 teljesítmény tipp ASP.NET webalkalmazásokhoz

2013.03.12. 10:00 Hozzászólás

A fejlesztői segédeszközeiről híres RedGate kiadott egy ingyenes, 50 oldalas e-bookot 50 ways to avoid, find and fix ASP.NET performance issues címmel. A könyvben MVP-k SQL Server, ORM, .NET Framework, IIS és ASP.NET tippjeit gyűjtötték össze, melyek alkalmazásával jobb teljesítményt facsarhatunk ki a webalkalmazásainkból.

A könyv 50 javaslatot tartalmaz 50 oldalon, ebből talán már látszik, hogy nem az a célja, hogy minden technikai részlettel megismertesse az olvasót, hanem hogy felhívja a figyelmet olyan beállításokra vagy mintákra, amelyek mellett hajlamosak vagyunk nap mint nap elmenni. Ennek megfelelően a könyvben kevés újdonság van azok számára, akik már foglalkoztak ASP.NET teljesítmény tuningolással, számukra az igazi érték, hogy szinte ellenőrző listaként használható a könyv. Aki számára pedig új ez a terület, annak jó kiinduló pontot adhatnak a könyvben található témakörök és kulcsszavak a további tájékozódáshoz.

A könyv letölthető innen: http://www.red-gate.com/50ways

 

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

Mockupkészítő eszközök

Kevés olyan hasznos dolog van a fejlesztő életében, mint a mockupkészítő eszközök. Ezek olyan szoftverek, amelyek segítségével leskiccelhetjük, hogyan fog kinézni az alkalmazásunk. Bár a mockupok tipikusan fapadosan kinéző drótváz ábrák, mégis számtalan előnyük van:

  • Legalább egyszer mi is végiggondoljuk, hogy milyen funkciókat szeretnénk, és azok hogyan fognak megjelenni a felhasználói felületen. Akár a teljes alkalmazást lerajzolhatjuk, és a hagyományos képfájlokkal ellentétben a mockupkészítő eszközök által biztosított interakcióknak köszönhetően akár ki is próbálhatjuk.
  • Az ábra felett eszmét cserélhetünk másokkal, akár a megrendelővel, akár más tervező/fejlesztő kollégákkal. Amikor mindkét fél látja, amiről beszélnek, sokkal fókuszáltabb és hatékonyabb tud lenni a megbeszélés. Ha valakinek ötlete van, azt sokkal gyorsabban át lehet vezetni egy statikus ábrán, mint egy élő kódon.
  • Az ábra mellé villámgyorsan feljegyezhetjük a legjobb ötleteinket (pl. “A Mentés működjön Ctrl+S-re is.”), ami sokkal gyorsabb, mint dokumentációt írni, arról nem is beszélve, hogy egy rövid feljegyzést sokkal valószínűbb, hogy elolvas az implementációt végző fejlesztő.
  • A mockup alapján szinte mindenki, a grafikus, a sitebuilder, a fejlesztő azonnal el tud kezdeni dolgozni és még a megrendelő is látja, hogy halad a projekt.
  • Egyes eszközök kódvázat is tudnak generálni az ábrából, ami talán még használható kiindulópont is lehet a fejlesztés során.

Összességében azt tapasztaltuk, hogy a mockupok egyértelműbbé teszik mindenki életét, és bár látszólag plusz munkát igényelnek, a félreértések megszűntetésével végül spórolhatunk velük.

Szerintem teljesen mindegy, hogy milyen eszközzel készülnek a mockupok, a lényeg, hogy a rajzolás ne igényeljen több időt, mint majd az implementáció. Ennek fényében én sokáig papíron mockupoltam, de ma már vannak egészen hatékony eszközök.

Balsamiq Mockups

A Balsamiq egy Adobe Air-re épülő, kifejezetten statikus mockup készítésére tervezett alkalmazás. A használata pofonegyszerű, talán ennek köszönhetően vált a legelterjedtebb eszközzé ezen a piacon. A Balsamiq nem ingyenes, de 79 dollárt simán megér, mi is ezt használjuk már évek óta.

Ami tetszik benne:

  • Bármilyen alkalmazást megtervezhetünk benne, legyen az desktop, webes vagy mobil app:

balsamiq-components

  • A Balsamiq már annyira elterjedt, hogy kis keresgéléssel kész template-eket találhatunk a neten, például akár Windows Phone vagy Windows 8 fejlesztéshez.
  • Ahogy a fenti ábrán is látszik, a beépített vezérlők kifejezetten rondák (bár az újabb Balsamiq verzióban már “szép” skint is lehet rájuk húzni), ami azért nagyon praktikus, mert egy megbeszélés során a dizájn nem vonja el a figyelmet a lényegről, ami mockupok esetén a funkció, a layout és a navigáció. Aki találkozott már olyan ügyféllel, aki 2-3 órát képes volt elfilózni azon, hogy egy-egy ikon mennyire felismerhető, az tudja, hogy miért preferálom a ronda mockupot.
  • Az ábrák képesek minimális interakcióra, ugyanis valamennyi vezérlő kattintható és a kattintás hatására képes elnavigálni minket egy másik oldalra. Egy popup ablakot ennek megfelelően úgy rajzolunk, hogy duplikáljuk a teljes ábrát, majd a másolatra rárajzoljuk a felugró ablakot. Ez ugyan plusz munka, de szinte mindent kipróbálhatóvá tesz.
  • A vezérlők újrafelhasználható egységekbe csomagolhatók, így például egy menüt, vagy egy master page-et elég egyszer megrajzolnunk és egy helyen karbantartanunk.
  • A Balsamiq-nak van teljes képernyős vetítő üzemmódja, ami egyeztetéseken nagyon praktikus szokott lenni.
  • Az ábrákat képes PDF dokumentumba exportálni, ráadásul úgy, hogy kattinthatóak maradnak, tehát egy sima PDF olvasóval kipróbálhatóvá válik a mockup.

Néhány tanács azoknak, akik most kezdenek a Balsamiq megismeréséhez:

  • Vásárlás előtt próbáld ki a szoftvert, van belőle trial és böngészőben futtatható próba változat is.
  • Nézd végig a vezérlőket, hiszen nincs bosszantóbb annál, mint amikor az ember megrajzol egy összetettebb UI elemet, azután pedig kiderül, hogy készen is behúzhatta volna az eszköztárról.
  • Mielőtt nagyobb rajzolásba fogsz, keress a neten kész template-eket, például a MockupsToGo oldalán jó adag található.
  • A Balsamiq használata egyszerű, hamar rá lehet érezni, mégis azt javaslom, hogy fusd végig a dokumentációt, megéri. Sőt, ha van 2 órád, végigolvasni is megéri. Az újrafelhasználható komponensek (azaz Symbols) használata talán nem teljesen magától értetődő, de arról is van doksi.
  • A gyorsbillentyűk használata sokat dobhat a tempón.
  • A fájlnevekhez már az elején találj ki egy elnevezési konvenciót. Ez azért fontos, hogy az oldalak közötti linkelés tisztán fájlnév alapján megy (nincs projekt fájl), és ha átnevezel egy fájlt a diszken, nem fognak működni a rá mutató linkek.

Honlap: http://balsamiq.com

Infragistics Indigo Studio

Az Indigo Studio egy pár hete megjelent új eszköz, ami a Balsamiq monopóliumát igyekszik megdönteni az alábbiakkal:

  • Szebb, élethűbb mockupok készíthetők vele (bár szerintem ez nem előny).
  • Képes összetettebb interakciókra és animációkra.
  • Tud Balsamiq fájlt importálni (ez mekkora ötlet ;-) .
  • A V1 verzió ingyenes és az is marad, majd csak annak kell fizetni, aki a V2 verziót akarja használni. Ez egy érdekes megoldás arra, hogy egy új termék betörjön a piacra (még érdekesebb lenne, ha a letöltés egyszerűbb lenne).

Az első ismerkedéshez készítettek egy 6 részes videó sorozatot, szerintem azzal érdemes kezdeni.

Mivel futó projektjeinkben nem akarunk váltani, ezért még nem ástam bele magam az Indigo Studio használatába, de majd a következő projekt előtt megnézem. Van már vele valakinek gyakorlati tapasztalata?

Visual Studio 2012

A VS 2012 egyik rejtett szépsége, hogy beépít a PowerPointba egy Storyboarding nevű fület, amely olyan elemeket tartalmaz, amiket akár mockup rajzolásra is használhatunk. Azért “akár”, mert ahogy a neve is mutatja, itt nem kifejezetten a UI a fontos, hanem a felhasználáshoz kapcsolódó sztori.

powerpoint-storyboard-shapes

A panel alján található Find more Storyboard Shapes online link a Visual Studio Gallery Storyboard Shapes kategóriájába visz, ahonnan további rajzelemeket tölthetünk le. Ez a kategória egyelőre nem tartalmaz sok elemet, de azért vannak már használhatók, természetesen némelyik fizetős. Itt van például a Windows8Templates:

Windows8Templates-Storyboard-Shapes-Capture1

A PowerPoint óriási előnye, hogy alig kell tanulni a használatát, ráadásul minden gépen elérhető. Ha bővülne a közösségi kínálat, gyorsan nagyon használhatóvá válna.

Pár bevezető link:

 

Ti szoktatok mockupolni, és ha igen, milyen eszközt használtok mockup elkészítésére?

 

URL megnyitása WebDAV-on át

2013.02.22. 17:08 Hozzászólás

Aki SharePointtal foglalkozik, annak hasznos lehet az alábbi két kódrészlet, amelyek ugyanarra szolgálnak: megnyitnak egy URL-t “web folder” nézetben, azaz WebDAV-on át, persze csak IE-ben.

<span style="behavior:url('#default#httpFolder');" 
      onclick="this.navigateFrame('https://intranet', '_blank')">
  Megnyitás
</span>     

<a href="#" target="_blank"
   style="behavior:url('#default#AnchorClick');"
   folder="https://intranet">
  Megnyitás
</a> 

Részletes leírás itt: About Web Folder Behaviors

 

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

T4MVC: ASP.NET MVC stringmentesen

Az ASP.NET MVC egyik kellemetlensége, hogy alapértelmezés szerint sok helyen stringekkel hivatkozunk a controllerekre, actionökre és view-kra. Aki valaha készített már ilyen projektet, az biztosan írt már az alábbihoz hasonló sort egy actionbe:

  return View( "Index" );

vagy épp egy view-ba:

  @Html.ActionLink( "Bejelentkezés", "Login" )

A szépséghibát a stringek jelentik, ugyanis ha ott hibázunk, az csak futási időben derül ki.

Ezen segít a T4MVC projekt, amit legegyszerűbben NuGet csomagként illeszthetünk be az alkalmazásunkba:

t4mvc-nuget

Ha már vannak a projektünkben controllerek, akkor ne lepődjünk meg, hogy a NuGet telepítő egy kicsit átírja őket:

t4mvc-warnings

Sőt kapunk néhány extra fájlt is a projektünkhöz:

t4mvc-files

Cserébe ezek után már típusosan hivatkozhatunk a nézetekre:

  return View( Views.Index );

az actionökre:

  @Html.ActionLink( "Bejelentkezés", MVC.Home.Login() )

és még sok minden másra, amiről bővebben a dokumentációból tájékozódhatunk.

Mivel a háttérben T4 template-ek alapján történik kódgenerálás, felmerülhet a kérdés, hogy mi történik, ha például felveszünk egy új actiont? Azt fogjuk tapasztalni, hogy simán hivatkozhatunk rá view-ból, még az IntelliSense is fel fogja kínálni, csak éppen futási időben fog elszállni ezzel a hibával (itt azért egy pillanatra elgondolkozhatunk, hogy vajon nem épp ezt akartuk-e elkerülni):

T4MVC was called incorrectly. You may need to force it to regenerate by right clicking on T4MVC.tt and choosing Run Custom Tool

Szerencsére nagyon beszédes hibaüzenet, és ha követjük, valóban meg is oldódik a probléma. Ha még ezzel sem szeretnénk foglalkozni, akkor használhatjuk az AutoT4MVC bővítményt, amely figyeli, hogy módosulnak-e a fájljaink, és szükség esetén automatikusan újrafuttatja a kód generátort.

 

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

Firefox kontra UTF-8

Az Egyetem MSDNAA oldalának frissítésekor futottam bele egy érdekes jelenségbe: saját gépemen tesztelve az oldalak teljesen jól működtek, felmásolva a szerverre viszont nem egészen. Szinte az összes böngészőben rendben volt minden, kivéve Firefoxban, ahol zagyvaság jelent meg a magyar ékezetes karakterek helyett.

Ellenőriztem a fájlokat, korrektül UTF-8-ban voltak elmentve, még a byte-order-mark is ott volt az elején – amit mondjuk nem volt nehéz észrevenni, hiszen a Firefox lelkesen ki is rajzolta az oldal elejére: 

Mivel szép új HTML5 oldalakról van szó, ott virít bennük a <meta charset="utf-8" /> sor, sőt még a klasszikus Content-Type sort is beletettem, hiába.

A gyors ellenőrzések után vissza a kályhához, elő a Fiddlert, ahol már látszott is a hiba oka. Ez a fejléc sor jött a szervertől:

Content-Type: text/html; charset=iso-8859-1

Ezen a ponton megvilágosodtam és rájöttem, hogy a régi oldalak miért voltak UTF-8 helyett ISO-8859-1-ben elmentve: mert a webszerver ezt a charsetet kényszeríti rá! A fejlécben lévő információ pedig Firefox esetén felülírja az oldalban lévő beállítást.

Tekintve, hogy a site egy Apache szerveren fut shared hosting környezetben, ahol se ASP.NET, se PHP, se admin jogom, szerver oldali kódból nem tudtam felülírni a fejléc mezőt. A megoldás mégis egyszerű lett, csak ezt az egyetlen sort kellett a webhely gyökerében lévő .htaccess fájlba beleírni:

AddDefaultCharset UTF-8

A webhely gyökerében lévő beállítás szerencsére öröklődik az alkönyvtárakra is.

 

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

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

Csatlakozz a 58 követőhöz

%d bloggers like this: