Další ferátkou byla cesta kolem horského jezera Idro. Má jméno Sasse a více informací lze zde. To je necelou hodinku jízdy od severního konce Gardského jezera a leží i výše - a je tam tedy i o poznání chladněji. A zatímco u Gardy to koncem října ještě žije, tady sezona už skončila. Velké parkoviště bylo zcela prázdné a na celé feratě jsme potkali jen čtyři další lidi. A panovalo zde ticho.
úterý 9. prosince 2014
neděle 7. prosince 2014
Vybaveni na cesty autem - chlazení
Převoz potravin autem a v chladu byla vždy výzva. Na kratší vzdálenosti stačí polystyrénová krabice, zmražené potraviny a chladící vložky - tenhle systém používáme už roky a je to spolehlivý způsob přepravy většího množství potravin na kratší vzdálenosti. Ale pokud se jede někam na více dnů a není možné využívat lednice, nelze se spolehnout na box, respektive ten není moc použitelný.
pátek 5. prosince 2014
Razor a email
V přechozím příspěvku jsem ukázal, jak využít Razor i mimo web aplikace. Nyní popíši, jak tohoto přístupu využít v případě, že chceme v aplikaci vytvořit email a ten poslat uživateli. Email bude obsahovat i obrázky a přílohu.
emailLayout.cshtml
Vytvoření šablony pro email
Šablony jsou vlastně dvě. V první je vlastní obsah mailu a tato šablona využívá jinou jako svoji obálku - to je vhodné pro případy, kdy bude potřeba více emailů a všechny by měly mít například jednotný vzhled.
email.cshtml
@* Generator: Template *@
@functions{
public string Recipient { get; set; }
public string Sender { get; set; }
public string Content { get; set; }
}
@{ Layout = new emailLayout();}
<img alt="Logo" src="cid:logo" />
<table width="550" class="headerText">
<tr><td>Hello Mr.@Recipient</td></tr>
<tr><td>This is my message for you: @Content</td></tr>
<tr><td>Regards, @Sender</td></tr>
</table>
emailLayout.cshtml
@* Generator: Template *@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-type" content="text/html;charset=UTF-8" /> <style type="text/css"> body { font-family: "Lucida Grande","Helvetica Neue",sans-serif; font-size: 12px; color: #333333; background: White; } </style> </head> <body> @RenderBody() </body> </html>
Vygenerování emailu
Získání HTML mailu je jednoduché - jak ze šablony vyrobit text už bylo ukázáno v předchozím díle, nyní jen použijeme metodu třídy AlternateView k získání HTML obsahu:
Code:
MailMessage mail = new MailMessage(); var htmlContent = (new email { Sender = "Martin", Recipient = "John", Content = "You win!!!" }).TransformText().Trim(); var htmlView = AlternateView.CreateAlternateViewFromString(htmlContent, new ContentType("text/html")); mail.AlternateViews.Add(htmlView);
Vkládání obrázků
V kódu šablon si můžete všimnout i značek pro zobrazení obrázků. Pokud má email obsahovat obrázky, máte tyto tři možnosti:
- v tagu img odkázát na existující, veřejně dostupný obrázek na sítí
- vložit obrázek do emailu a odkázat na něj v tagu img pomoci cid:název
- vložit obrázek jako base64
Z textu šablon vyplývá, že použiji druhou možnost - jako hodnotu ContentId použijeme hodnotu zadanou za cid: v src atributu příslušeného img tagu:
var attachResource = new LinkedResource(new MemoryStream(<byte[]>)); attachResource.ContentId = <resourceID>; htmlView.LinkedResources.Add(attachResource);
Vkládání příloh
Pokud chceme k emailu přiložit i přílohu, jde to podobně jednoduše - nejprve si vytvoříme příslušný objekt a pak je přidáme do kolekce příloh mailu:Attachment att = new Attachment(new MemoryStream(<byte[]>), attachmentName); mail.Attachments.Add(att);
Tipy
Pro testování posílání emailů lze použít utilitku Smtp4Dev a do config souboru aplikace přidáme následující nastavení:
<system.net>
<mailSettings>
<smtp from="mail@test.com">
<network host="localhost" port="25"/>
</smtp>
</mailSettings>
</system.net>
Výsledek
Po spuštění pak obdržíme email, který nás informuje o výhře:středa 3. prosince 2014
Využití Razor mimo web
Při programování aplikací je často nutné vygenerovat nějaký text - například email - který je částečně pozměněn - například se mění oslovení (pan-paní), jméno (Martin-Petr) apod. Obvyklé postupy jsou buď tvrdě kódové - tedy skládání textu přímo v kódu za využití například StringBuilderu a nebo se použije textový soubor sloužící jako předloha (šablona), kde se vyhledávájí značky a místo nich se vkládá určitá hodnota.
Pokud ale programujete web aplikace v ASP.NET, určitě jste se setkali s MVC a Razorem - a pokud se vám tento přístup líbí - tedy možnost vytvořit si šablonu, do které se v určitých místech vkládají hodnoty a která umožňuje provádět i složitější operace - je možné podobný přístup použít i v non-web aplikacích. Stručně ukáži jak na to.
Co je nutné?
Postupy jsou popsány mnohem stručněji v jiných příspěvcích dostupných na internetu, tak to vezmu stručně:
Nejprve nainstalujte si RazorGenerator za použití následujícícho postupu
- Ukončete všechny běžící instance Visual Studia - nechte běžet jen jednu.
- Běžte do Tools -> Extension and Updates a vyhledejte Razor Generator
- Naistalujte to
Poté pro každý projekt/solution, ve kterém chcete Razor používat, proveďte toto:
- Běžte do Tools –> NuGet Package Manager –> Package Manager Console
- Zadejte a spusťte" “PM>Install-Package RazorGenerator.Templating”
A to je vše, nyní již můžete Razor použít ve své aplikaci.
Vytváříme šablonu - příklad
Jak Razor použít popíši na příkladu jednoduché konzolové aplikace:
- Do projektu vložte novou položku - greetings.cshtml
- Ujistěte se, že tato položka má ve svých vlastnostech jako hodnotu Custom Tool nastaveno RazorGenerator

- Zadejte tento kód a ulože změny - na rozdíl od použítí v MVC nemá tato šablona vlastnost Model, ale díky bloku functions můžeme definovat jednotlivé vlastnosti a objekty - nejsme tedy vázání na jeden view model jako v případě MVC:

- Vraťte se do Program.cs a do Main metody vložte následující kód:

- Spusťte aplikaci a na obrazovce uvidíte:

Nezapomeňte:
Instalace Nuget balíčku začal váš projekt používat knihovnu RazorGenerator.Templating a tak ke scému běhu potřebuje další knihovny, takže nezapomeňte přidat tyo knihovny při šíření své aplikace:
- System.Web.Extensions.dll
- System.Web.Helpers.dll
Zjednodušený přehled výše uvedeného jsem shrnul na jednu stránku A4, kterou si je možné stáhnout zde.
úterý 18. listopadu 2014
Zábavní parky okolo ČR
Bohužel nám v ČR chybí pořádný zábavní park a tak se musí vždy do zahraničí. Tady je přehledná mapka zábavních parků v Evropě - ty lepší jsou zvýrazněny hvězdičkou. Snažil jsem se zahrnout všechny parky, které mají něco, co alespoň trochu připomíná horskou dráhu.
Jak je vidět, naprostá většina parků leží v Německu - zejména asi jeden z nejlepších parků v Evropě Europa Park.
Ne všechny parky v přehledu stojí za návštěvu, - například bych varoval před polským parkem Wesole Miasteczko - je to asi tak nejhorší park, co jsme kdy navštívil, díky neschopnosti obsluhy neskutečné čekací doby i když byl park prázdný. U jiných parků je třeba zvážit i vhodný věk na návštěvu. Rakouský Family Park se hodí spíše pro menší děti, německý Legoland asi nadchne děti do 10ti let a pak už je to horší a tak podobně.
pondělí 17. listopadu 2014
Feraty u jezera Lago di Garda 1 - Colodri a Drena
čtvrtek 6. listopadu 2014
Stránkování v MVC
Tenhle článeček je o stránkování záznamů v MVC trochu jinak - tak, aby jednotlivé části (controller's actions, models, views) zůstaly co nejvíce jednoduché.
Zdrojový kód je dostupný zde.
Pro zobrazení seznamu bude sloužit generická třída - takže ani tento příklad nebude pevně svázán s třídou UserViewModel, ale generickou třídu budeme moci použít s jakoukoliv třídou, z níž chceme zobrazovat data.
a ještě musíme mít třídu, která bude držet "stránkovácí" informace:
Objekt této třídy bude vlastně jen držet číslo aktuální stránky, velikost stránky a celkový počet stránek.
a view:
Nejprve se metoda pokouší najít hodnotu parametru předávaného metodě kontroleru - tedy PagingViewModel. Pokud takový parametr nenajde, tak jej vytvoří a nastaví velikost stránky a první stránku jako aktuální. Zároveň tyto hodnoty vloží i do kolekce RouteData. Tato kolekce je MVC používáná při bindování a pokud tedy budeme později volat metodu Paging, tak MVC použije data z této kolekce pro vytvoření parametru (instance třídy PagingViewModel) předávaného do této metody.
Po spuštění metody se naplní kolekce a zároveň se zjistí, kolik záznamů je celkem k dispozici. Což je ten správný okamžik pro spuštění metody OnActionExecuted, která vypočte celkový počet stránek a získá tak poslední hodnotu, kterou je nutno uložit do kolekce RouteData, aby MVC mohlo později, při volání metody Paging, vytvořit plnohodnotnou instanci třídy PagingViewModel.
Můžete si také všimnout, že je kontrolován typ příchozího volání a pokud se jedná o Ajax volání, je výsledek změněn na PartialView - takže se rendreju pouze view odpovídající danému kontroleru a master view je ignorováno - vrací se tak pouze zrendrovaná tabulka a nikoliv celá stránka.
Tento atribut je pak použit pro dekorování akce a zároveň nastavuje velikost stránky:
Může se použít na libovolnou akci, která vyžaduje pro své výsledky stránkování. Vývojář se o stránkování nemusí starat a v kontroleru se tedy může soustředit pouze na získání dat.
Zdrojový kód je dostupný zde.
Models
Aby to nebylo moc složité, bude se zobrazovat seznam jmen, tedy jako základní třída nám poslouží toto:public class UserViewModel { public string FirstName { get; set; } public string LastName { get; set; } }
Pro zobrazení seznamu bude sloužit generická třída - takže ani tento příklad nebude pevně svázán s třídou UserViewModel, ale generickou třídu budeme moci použít s jakoukoliv třídou, z níž chceme zobrazovat data.
public interface IItemListInfo { int TotalItems { get; } } public class ItemListViewModel<T> : IItemListInfo { private IEnumerable<T> items; private int totalItems; public ItemListViewModel(IEnumerable<T> items, int totalItems) { this.items = items; this.totalItems = totalItems; } public IEnumerable<T> Items { get {return this.items;} } public int TotalItems { get { return this.totalItems; } } }
a ještě musíme mít třídu, která bude držet "stránkovácí" informace:
public class PagingViewModel { public int PageNumber { get; set; } public int PageSize { get; set; } public int Pages {get;set;} }
Controller - poprvé
Akce v kontroleru bude jednoduchá - hlavním úkolem je načíst daný počet dat (=počet záznamů na stránku) pro danou stránku (počet stránek)
public ActionResult Index(PagingViewModel paging) { ItemListViewModel<UserViewModel> model = this.GetUsers(paging.PageSize, paging.PageNumber); return View(model); }
Views
Ve view dojde k zrendrování informací a i k vykreslení navigační části. První view je docela jednoduché a vykreslí informace o uživateli - pro vykreslení navigační části pak předá řízení zpět do kontroleru a zavolá akci "Paging"
@using MvcPagingExample.Models; @model ItemListViewModel<UserViewModel> @{ ViewBag.Title = "Home Page"; } <div class="list"> <h2>List of Users</h2> <table> <thead> <th width="120px">First name</th> <th width="120px">Last name</th> </thead> @foreach (UserViewModel user in Model.Items) { <tr> <td>@user.FirstName </td> <td>@user.LastName</td> </tr> } </table> <br/> @{Html.RenderAction("Paging");} </div>
Controller - podruhé
Tato metoda může být použita pro vykreslení stránkování libovolného seznamu - odpovídající view jen využívá javascript pro ajax volání zpět na server a vrácenou hodnotou nahrádí stávající obsah:[ChildActionOnly] public ActionResult Paging(PagingViewModel paging) { return PartialView(paging); }
a view:
@using MvcPagingExample.Models; @model PagingViewModel <script type="text/javascript"> $(document).ready(function () { jQuery("a").click(function () { var $anchor = jQuery(this); var url = $anchor.closest('.ajaxPaging').attr("data-source"); jQuery.get( url, { PageNumber: $anchor.attr("rel")}, function (data) { jQuery(".list").replaceWith(data); }); }); }); </script> <div class="ajaxPaging" data-source="@Request.Url.AbsolutePath"> @NaviLink(active: Model.PageNumber > 1, targetPageNumber: 1, label: "first") @NaviLink(active: Model.PageNumber > 1, targetPageNumber: (Model.PageNumber - 1), label: "previous") <b>page @Model.PageNumber of @Model.Pages</b> @NaviLink(active: Model.PageNumber < Model.Pages, targetPageNumber: (Model.PageNumber + 1), label: "next") @NaviLink(active: Model.PageNumber < Model.Pages, targetPageNumber: Model.Pages, label: "last") </div> @helper NaviLink(bool active, int targetPageNumber, string label) { if (active) { <a href="#" rel="@targetPageNumber">@label</a> } else { @label } }
Prvotní nastavení
Zbývá ještě ošetřit případ, kdy při prvním volání akce není žádné stránkování nastaveno. K tomu slouží atribut třída, která dědí z třídy ActionFilterAttribute a která nabízí dvě metody - jednu spouštěnou před provedením vlastní akce kontroleru (OnActionExecuting) a druhou, která se provadí po vykonání akce v kontroleru (OnActionExecuted).public override void OnActionExecuting(ActionExecutingContext filterContext) { var paging = filterContext.ActionParameters.Select(p => p.Value as PagingViewModel).Where(f=> f !=null).FirstOrDefault(); if (paging != null) { paging.PageSize = PageSize; filterContext.RouteData.Values.Add("PageSize", this.PageSize); if (paging.PageNumber == 0) { filterContext.RouteData.Values.Add("PageNumber", 1); paging.PageNumber = 1; } } base.OnActionExecuting(filterContext); }
Nejprve se metoda pokouší najít hodnotu parametru předávaného metodě kontroleru - tedy PagingViewModel. Pokud takový parametr nenajde, tak jej vytvoří a nastaví velikost stránky a první stránku jako aktuální. Zároveň tyto hodnoty vloží i do kolekce RouteData. Tato kolekce je MVC používáná při bindování a pokud tedy budeme později volat metodu Paging, tak MVC použije data z této kolekce pro vytvoření parametru (instance třídy PagingViewModel) předávaného do této metody.
Po spuštění metody se naplní kolekce a zároveň se zjistí, kolik záznamů je celkem k dispozici. Což je ten správný okamžik pro spuštění metody OnActionExecuted, která vypočte celkový počet stránek a získá tak poslední hodnotu, kterou je nutno uložit do kolekce RouteData, aby MVC mohlo později, při volání metody Paging, vytvořit plnohodnotnou instanci třídy PagingViewModel.
public override void OnActionExecuted(ActionExecutedContext filterContext) { var model = filterContext.Controller.ViewData.Model as IItemListInfo; if (filterContext.HttpContext.Request.IsAjaxRequest()) { ViewResult result = filterContext.Result as ViewResult; filterContext.Result = new PartialViewResult() { TempData = result.TempData, View=result.View, ViewData=result.ViewData, ViewEngineCollection=result.ViewEngineCollection}; } if (model != null) { filterContext.RouteData.Values.Add("Pages", (int) Math.Ceiling( (double) model.TotalItems/this.PageSize)); } base.OnActionExecuted(filterContext); }
Můžete si také všimnout, že je kontrolován typ příchozího volání a pokud se jedná o Ajax volání, je výsledek změněn na PartialView - takže se rendreju pouze view odpovídající danému kontroleru a master view je ignorováno - vrací se tak pouze zrendrovaná tabulka a nikoliv celá stránka.
Tento atribut je pak použit pro dekorování akce a zároveň nastavuje velikost stránky:
[Paging(PageSize = 5)] public ActionResult Index(PagingViewModel paging) { ItemListViewModel<UserViewModel> model = this.GetUsers(paging.PageSize, paging.PageNumber); return View(model); }
Může se použít na libovolnou akci, která vyžaduje pro své výsledky stránkování. Vývojář se o stránkování nemusí starat a v kontroleru se tedy může soustředit pouze na získání dat.
Přihlásit se k odběru:
Příspěvky (Atom)
