BLOGas.lt
Sukurk savo BLOGą Kitas atsitiktinis BLOGas

Savaitės video - Optimizing ASP.NET Application performance: tough but necessary

Parašė Sergejus | 2011-12-12 20:21

Šį kartą jūsų dėmesiui siūlau vieną praktiškiausių savo pristatymų iš TechDay 2011 - Optimizing ASP.NET Application performance: tough but necessary.


Rodyk draugams

SquishIt - JavaScript ir CSS failų apjungimas bei minifikavimas

Parašė Sergejus | 2011-11-28 21:26

Web aplikacijų optimizavimas yra sudėtingas ir kompleksiškas uždavinys. Egzistuoja nemažai patarimų nuo ko pradėti ir ką daryti. Dalį tokių patarimų aš vaizdžiai pademonstravau savo pristatymo metu TechDay 2011. Tarp rodytų technikų buvo ir daugeliui Web programuotojų gerai žinomas JavaScript ir CSS failų kombinavimas bei minifikavimas. Failų kombinavimas leidžia ženkliai sumažinti naršyklės užklausų skaičių, o failų minifikavimas sumažina siunčiamo failo dydį (dažnai apie 30%).

ASP.NET 4.5 turės šį funkcionalumą prieinamą iš dežutės, bet ką daryti esamiems ASP.NET ir ASP.NET MVC programuotojams? Norėčiau rekomenduoti biblioteką SquishIt. Ji palaiko ne tik grynuosius JavaScript bei CSS failus, bet ir JavaScript kalbą CoffeeScript bei CSS kalbą less. Pažymėtina, SquishIt palaiko iš karto kelias trečių šalių suspaudimo bibliotekas: Microsoft Ajax Minifier, Yahoo YUI Compressor, Google Closure ir pan.

Žemiau pateiksiu kodą, kurį naudoju Lietuvos .NET vartotojų grupės mobilioje apklausoje:

<%= SquishIt.Framework.Bundle.Css()
    .Add("~/Content/jquery.mobile.structure-1.0.css")
    .Add("~/Content/jquery.mobile-1.0.css")
    .Add("~/Content/style.css")
    .Render("~/Content/styles_#.min.css")%>

<%= SquishIt.Framework.Bundle.JavaScript()
    .Add("~/Scripts/jquery-1.6.4.js")
    .Add("~/Scripts/jQuery.tmpl.js")
    .Add("~/Scripts/init.js")
    .Add("~/Scripts/jquery.mobile-1.0.js")
    .Add("~/Scripts/jquery.cookie.js")
    .Add("~/Scripts/json2.js")
    .Add("~/Scripts/functions.js")
    .Render("~/Scripts/scripts_#.min.js")%>

Kaip matote, rezultatas bus išsaugotas failuose styles_#.min.css ir scripts_#.min.js, kur vietoje # bus galutinio failo MD5 hashas. ASP.NET MVC atveju užtenka <%= … %> pakeisti į @Html.Raw(…).

Rodyk draugams

Savaitės video - ASP.NET MVC ir NuGet

Parašė Sergejus | 2011-11-06 13:40

Šios savaitės video – Domantas Jovaišas, ASP.NET MVP, pasakoja apie ASP.NET MVC ir NuGet.

Rodyk draugams

ASP.NET greitaveikos optimizavimo įrankiai

Parašė Sergejus | 2011-07-17 17:23

Ryšium su tam tikrais darbais, nusprendžiau surašyti dėmesio vertus įrankius, skirtus ASP.NET puslapių greitaveikos optimizavimui. Jeigu žinote daugiau įrankių – rašykite komentaruose!

  • YSlow ir Page Speed – ko gero populiariausi optimizavimo įrankiai, kurie ne tik įvertina jūsų puslapio greitaveiką, bet ir pateikia patarimus kaip galima ją (greitaveiką) pagerinti;
  • SenSEO ir SEO Toolkit – įvertina jūsų puslapių atitikimą paieškos variklių optimizavimo (angl. Search Engine Optimization, SEO) kriterijui;
  • SmushIt ir PunyPNG – online įrankiai skirti paveiksliukų optimizavimui, panaikinant meta informaciją bei vykdant papildomą suspaudimą be kokybės praradimo;
  • Image Optimizer – Visual Studio įskiepys skirtas paveiksliukų optimizavimui, panaudojant SmushIt ir PunyPNG servisus;
  • Ajax Minifier, YUI Compressor ir Closure Compiler – populiariausi JavaScript ir CSS minifikavimo (optimizavimo) įrankiai;
  • FileBundler, SquishIt – bibliotekos, skirtos susijusių failų apjungimui į vieną (JavaScript, CSS ir pan.);
  • Windows Azure CDN Helpers – pagalbinė klasė darbui su CDN;
  • Sprite and Image Optimization Framework – biblioteka, mokanti iš katalogo su paveiksliukais pagaminti vieną bendrą paveiksliuką (angl. Sprite) ir susijusį CSS failą;
  • Straipsnis, aprašantis HTTP kompresijos konfigūravimą IIS7.

Rodyk draugams

ASP.NET MVC puslapių greitaveikos stebėjimas su MiniProfiler

Parašė Sergejus | 2011-06-26 11:38

Prieš kurį laiką rašiau apie Stack Overflow komandos sukurtą Dapper .NET biblioteką. Šiandien norėčiau trumpai aptarti kitą jų biblioteką – Mini Profiler for MVC 3. Jos pagalba galima labai paprastai sekti puslapių greitaveiką ir proaktyviai reaguoti į potencialias problemas. Iš karto norisi pasakyti, kad vienas didžiausių šios bibliotekos privalumų – mokėjimas matuoti SQL užklausų / sakinių vykdymo greitį.

Norėdami prijungti Mini Profiler prie egzistuojančios ASP.NET MVC 3 aplikacijos, užtenka tik kelių paprastų žingsnių:

  • pridėti NuGet paketą MiniProfiler:
    PM> Install-Package MiniProfiler
  • prie esamų JavaScript skriptų prijungti jQuery (jeigu dar nėra prijungtas) bei MiniProfiler skriptus:
    <head>
        <meta charset="utf-8" />
        <script src="@Url.Content("~/Scripts/jquery-1.6.1.min.js")" type="text/javascript"></script>
        @MvcMiniProfiler.MiniProfiler.RenderIncludes()
    </head>

  • Global.asax puslapyje startuoti ir stabdyti profailerį su kiekviena užklausa:

    protected void Application_BeginRequest()
    {
        if (Request.IsLocal)
        {
            MiniProfiler.Start();
        }
    }
    
    protected void Application_EndRequest()
    {
        MiniProfiler.Stop();
    }

  • vietoje standartinės DbConnection klasės naudoti klasę MvcMiniProfiler.Data.ProfiledDbConnection:

    var connection = ProfiledDbConnection.Get(new SqlConnection(connectionString))

Rezultate, be jokio papildomo programavimo gausite kažką panašaus:

image

Kaip matote, puslapio viršutiniame kairiame kampe atsirado informacija apie puslapio pasikrovimo laiką. Paspaudus ant jos, atsiras detalesnė informacija kartu su galimybe peržiūrėti įvykdytus SQL sakinius:

image

Norėdami pilnai išnaudoti MiniProfiler galimybes ir tiksliai žinoti kuri kodo dalis kiek laiko vykdoma, reikia naudoti žingsnius (angl. Step):

var profiler = MiniProfiler.Current;
using (var connection = ProfiledDbConnection.Get(new SqlConnection(connectionString)))
{
    using (profiler.Step("Žingsnio pavadinimas"))
    {
        // darbas su db
    }

    return View();
}

Žingsniai palaiko hierarchijas, tad esant poreikiui, galite labai tiksliai išmatuoti tiek bendrą, tiek skirtingų puslapio dalių greitaveiką.

Tiek šiam kartui, daugiau informacijos apie Mini Profiler for MVC 3 bei išeities kodą galite rasti oficialiame puslapyje.

Rodyk draugams

ASP.NET MVC3: Razor sintaksė

Parašė Sergejus | 2010-12-08 21:38

ASP.NET MVC3 jau ne už kalnų, o Release Candidate versiją galite parsisiųsti jau dabar. Kaip žinia, kartu su ASP.NET MVC3 atsiras ir naujasis atvaizdavimo variklis Razor. Šiame straipsnyje pabandysiu vaizdžiai paaiškinti naują Razor sintaksę, migruojant esamą ASP.NET MVC aplikaciją nuo WebForms atvaizdavimo variklio prie Razor.

Web aplikacijos struktūra

Paprastumo dėlei, aprašiau tokią minimalią ASP.NET MVC aplikaciją:

razor1

Kaip matyti, mes naudojame Layout.Master šabloninį puslapį, Person modelį bei PersonController kontrolerį. Kadangi mes keisime tik atvaizdavimo dalį – modelis ir kontroleris nesikeis ir atrodys taip:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Blog { get; set; }
    public string Twitter { get; set; }
    public IList<string> Interests { get; set; }
}
public class PersonController : Controller
{
    public ActionResult Index()
    {
        var model = new Person
        {
            FirstName = "Sergejus",
            LastName = "Barinovas",
            Blog = "sergejus.blogas.lt",
            Twitter = "sergejusb",
            Interests = new List<string>
            {
                "Windows Azure",
                "ASP.NET MVC",
                "C#",
                "Data Access"
            }
        };

        return View("Index", model);
    }

}

Perėjimas prie Razor

Norėdami pereiti prie Razor sintaksės, pakeisime Layout.Master ir Index.aspx failus į _Layout.cshtml ir Index.cshtml (c# su html).

Layout.Master

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <title>
        <asp:ContentPlaceHolder ID="Title" runat="server"/>
    </title>

    <link href='~/Content/Site.css' rel="stylesheet" type="text/css" />
    <script src='<%: Url.Content("~/Scripts/jquery-1.4.1.min.js")%>' type="text/javascript"></script>
    <%--
    <script src='<%: Url.Content("~/Scripts/jquery.validate.min.js")%>' type="text/javascript"></script>
    --%>

    <asp:ContentPlaceHolder ID="Head" runat="server" />
</head>
<body>
    <form id="Form" runat="server">
        <div id="main-container">
            <asp:ContentPlaceHolder ID="Body" runat="server" />
        </div>
        <div id="footer-container">
            <asp:ContentPlaceHolder ID="Footer" runat="server" />
        </div>
    </form>
</body>
</html>

_Layout.cshtml

<!DOCTYPE html>

<html>
<head>
    <title>@View.Title</title>

    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.4.1.min.js")" type="text/javascript"></script>
    @*<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>*@

    @RenderSection("Head", required: false)
</head>

<body>
    <div id="main-container">
        @RenderBody()
    </div>
    <div id="footer-container">
        @RenderSection("Footer")
    </div>
</body>
</html>

Index.aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Layout.Master" Inherits="System.Web.Mvc.ViewPage<OldWeb.Models.Person>" %>

<asp:Content ContentPlaceHolderID="Title" runat="server">
    About
</asp:Content>

<asp:Content ContentPlaceHolderID="Body" runat="server">
    <h2>About</h2>
    Name: <%: Model.FirstName %>
    <br />
    Surname: <%: Model.LastName %>
    <br />
    Blog: <%: String.IsNullOrEmpty(Model.Blog) ? "N/A" : Model.Blog %>
    <br />
    Interests:
    <ul>
        <% foreach (var interest in Model.Interests) { %>
            <li><%: interest %></li>
        <% } %>
    </ul>
</asp:Content>

<asp:Content ContentPlaceHolderID="Footer" runat="server">
    SB, 2010 ©
</asp:Content>

Index.cshtml

@inherits System.Web.Mvc.WebViewPage<Web.Models.Person>
@{
    View.Title = "About";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>About</h2>
Name: @Model.FirstName
<br />
Surname: @Model.LastName
<br />
Blog: @(String.IsNullOrEmpty(Model.Blog) ? "N/A" : Model.Blog)
<br />
Interests:
<ul>
    @foreach (var interest in Model.Interests) {
    <li>@interest</li>
    }
</ul>

@section Footer {
SB, 2010 ©
}

Manau aukščiau pateiktas kodas yra pakankamai suprantamas ir detalesnio paaiškinimo nereikalauja. Naujoji sintaksė man pasirodė intuityvi, švari bei greitai išmokstama. Daugiau informacijos apie Razor sintaksę galite rasti dokumente ASP.NET Web Pages Using The Razor Syntax.

Rodyk draugams

Paprastas būdas atvaizduoti Twitter pranešimus

Parašė Sergejus | 2010-08-31 14:03

Twitter pranešimų atvaizdavimas puslapiuose nėra naujas uždavinys. Egzistuoja bent keletas būdų kaip tai galima atlikti (įskaitant ir gatavus komponentus). Šiandien man prisireikė atvaizduoti su tam tikra hash žyme susijusius pranešimus ir padaryti tai norėjosi kuo paprasčiau (kad daugiau žmonių suprastų kas ir kaip yra daroma).

Pirmas dalykas kurį verta išnagrinėti – Twitter API dokumentaciją. Norint gauti su tam tikra hash žyme susijusius pranešimus, užtenka pasinaudoti metodu Search. Iš reikalingų metodo parametrų mums bus reikalingi keli:

  • callback – mūsų atveju tai bus anoniminė funkcija, todėl užrašas atrodys taip: callback=?
  • rpp – grąžinamų pranešimų skaičius
  • q – paieškos žymė, kur vietoje grotelių reikia rašyti %23, pvz., %23mvc (bus ieškoma #mvc)

Sakykime, mes turime tokį HTML kodą:

<div id="sidebar">
    <ul>
        <li>
            <h2>Info</h2>
            Blog: http://sergejus.blogas.lt </li>
        <li>
            <h2>Twitter</h2>
            <ul id="tweets">
            </ul>
        </li>
    </ul>
</div>

Norėdami į elementą tweets pakrauti Twitter pranešimus, aprašykime tokią JavaScript funciją:

function loadTweets(container, search) {
    var url = 'http://search.twitter.com/search.json?callback=?&rpp=10&q=' + search;
    $.getJSON(url, function (data) {
        var html = '';
        $.each(data.results, function (i, tweet) {
            html += '<li><a href="http://twitter.com/' + tweet.from_user + '">'
                 + tweet.from_user + '</a> ' + tweet.text + '</li>';
        });
        $(container).html(html);
    });
}

Kaip matyti, viskas labai paprasta:

  • kreipimąsi į Twitter API
  • gaunamas JavaScript objektas
  • suformuojamas LI elementas
  • galutinis HTML įrašomas į UL elementą

Svarbu tai, kad ši JavaScript funkcija gali ieškoti bet ką. Mūsų atveju loadTweets panaudojimas atrodytų taip:

<script type="text/javascript">
    $(document).ready(function () {
        loadTweets('#tweets', '%23pingy');
    });
</script>

Štai ir viskas – greitai, paprastai, suprantamai.

Rodyk draugams

ASP.NET MVC klaidų apdorojimas iš JavaScript

Parašė Sergejus | 2010-07-27 22:23

Šiais laikais praktiškai sunku įsivaizduoti Web aplikaciją, kuri nenaudotų Ajax technologijos. Vienas iš tradicinių Ajax panaudojimo pavyzdžių – asinchroninis duomenų pakrovimas (kuris su ASP.NET MVC ir jQuery tapo kaip niekada paprastas). Sakykime, mes turime kontrolerį Home:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult GetList()
    {
        throw new HttpException((int)HttpStatusCode.NotImplemented, "This method is not yet implemented");
    }
}

Ir turime puslapį Index.aspx:

<!DOCTYPE>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>ASP.NET MVC serverinių klaidų apdorojimas iš JavaScript</title>
    <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.4.1.js"></script>
</head>
<body>
    <div id="list_content"></div>
</body>
<script type="text/javascript">
    $.ajax({
        url: '/Home/GetList',
        cache: false,
        success: function (data) {
            $('#list_content').html(data);
        }
    });
</script>
</html>

Kaip matyti iš pateikto kodo, pasikrauna tuščias puslapis, kuris bando į DIV elementą asinchroniškai pakrauti duomenis kviečiant kontrolerio Home metodą GetList (kuris pas mus išmeta klaidą). Kaip teisingai pagauti ir apdoroti serverio klaidas iš JavaScript?

Pirma reikia papildyti mūsų kontrolerį perrašant metodą OnException (šią logiką aš dažniausiai iškeliu į bazinį kontrolerį):

protected override void OnException(ExceptionContext filterContext)
{
    if (filterContext.HttpContext.Request.IsAjaxRequest())
    {
        var statusCode = filterContext.Exception is HttpException ?
                        (filterContext.Exception as HttpException).GetHttpCode() :
                        (int)HttpStatusCode.InternalServerError;
        filterContext.HttpContext.Response.StatusCode = statusCode;
        filterContext.Result = new JsonResult
        {
            JsonRequestBehavior = JsonRequestBehavior.AllowGet,
            Data = new
            {
                filterContext.Exception.Message,
                filterContext.Exception.StackTrace,
                Url = filterContext.HttpContext.Request.RawUrl
            }
        };
        filterContext.ExceptionHandled = true;
    }
}

Išnagrinėkime kas yra daroma. Pirma patikrinama ar klaida kilo asinchroninio kreipinio metu. Jeigu taip – patikrinama ar tai HTTP klaida ir jeigu ne, suteikiamas HTTP501 (Internal Server Error) klaidos kodas. Galiausiai yra sudaromas JSON atsakymas, kuriame yra talpinama visa su klaida susijusi informacija (galima papildyti pagal poreikį). Tokiu būdu, vykdant asinchroninį kreipinį, kurio metu serveryje įvyksta klaida, mes gauname klaidos JSON objektą. Beliko šį objektą apdoroti HTML pusėje, tam papildysime jQuery ajax metodą:

<script type="text/javascript">
    $.ajax({
        url: '/Home/GetList',
        cache: false,
        success: function (data) {
            $('#list_content').html(data);
        },
        error: function (response) {
            var ex = $.parseJSON(response.responseText);
            alert("HTTP" + response.status + ": " + ex.Message);
        }
    });
</script>

Įvykus klaidai serverio pusėje, mes gauname klaidos JSON objektą (objekto response savybė responseText), kuriuo toliau galime operuoti apdorojant klaidą.

Tiek mano patirties iš ASP.NET MVC klaidų apdorojimo iš JavaScript. O kokius dar “triukus” jus taikote JavaScript klaidų apdorojimui?

Rodyk draugams

Keista IIS7 klaida - [PolicyException: Required permissions cannot be acquired]

Parašė Sergejus | 2010-05-19 21:37

Suinstaliavus Visual Studio 2010 viename iš kompiuterių, staiga negalėjau prieiti prie esamų ASP.NET puslapių. Bandant pasiekti puslapį – gaudavau klaidą:

[PolicyException: Required permissions cannot be acquired]

[FileLoadException: Could not load file or assembly 'NServiceBus …' or one of its dependencies. Failed to grant minimum permission requests. (Exception from HRESULT: 0x80131417)]

Pirmas įtarimas kuris man kilo: gal nusimušė teisės ar FullTrust. Tikrinimas nieko keisto neparodė, visos teisės buvo suteiktos. Tolesnė analizė parodė, kad nusimušė Load User Profile nustatymas IIS7 Web serveryje. Man padėjo tokie žingsniai:

  1. IIS Manager lange pasirinkti Application Pools
  2. Pasirinkti Web aplikacijos naudojamą Application Pool (mano atveju buvo DefaultAppPool)
  3. Paspausti Advanced Setting
    image 
  4. Atsiradusiame lange Process Model skiltyje parametrui Load User Profile pakeisti reikšmę į True
    image

Tikiuosi jums (ir man pačiam) ateityje, šitas straipsnis išsaugos pusvalandį-kitą.

Rodyk draugams

ASP.NET 4.0 ScriptManager dažnai užduodami klausimai (PDF)

Parašė Sergejus | 2009-12-15 01:16

Nusprendžiau jūsų patogumui savo klausimų / atsakymų seriją iš ASP.NET 4.0 ScriptManager sudėti į vieną PDF dokumentą ir padaryti prieinamą parsisiuntimui.

Rodyk draugams