<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><title type="text">Ivan Franjić Blog</title><subtitle type="text">.Net Development and Quality Assurance</subtitle><id>uuid:41a1ab41-890d-498f-b2bc-ddfe7f69e1e2;id=1</id><updated>2013-05-20T05:44:12Z</updated><author><name>Ivan Franjić</name><uri>http://www.ivanfranjic.net</uri><email>frennky@gmail.com</email></author><link rel="alternate" href="http://ivanfranjic.net/Feed/Atom" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/IvanFranjic/Atom" /><feedburner:info uri="ivanfranjic/atom" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry><id>http://www.ivanfranjic.net/2013/1/writing-faster-webdriver-tests</id><title type="text">Writing faster WebDriver tests</title><published>2013-01-15T22:41:00+01:00</published><updated>2013-01-15T22:41:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/qj9SvqkjVBc/writing-faster-webdriver-tests" /><content type="html">&lt;p&gt;Some day ago I met with a friend and had nice chat about testing. Eventually we came to a topic about Selenium. He's been using Selenium mostly for simple test cases, but now he was thinking of using it to test some reporting functionality.&lt;/p&gt;
&lt;p&gt;His concern was if Selenium is actually the right tool to help him with that. At that point I said that Selenium is the best free tool for functional testing of web apps that we have now, but it's another thing how good it actually is. It all depends how you use it and for what.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;The test case was fairly simple. Login, navigate to reporting, select a report type, input some parameters, generate report and than assert that data in reporting table is correct. The problem was that on average reports have a table with 50 rows and 10 columns, which means that he has 500 cells with data that needs to be verified.&lt;/p&gt;
&lt;p&gt;Now before we continue, lets refresh our memory how Selenium actually works. The Selenium server exposes a REST API to client WebDriver libraries. Each command we execute with client library is translated to a request to Selenium server.&lt;/p&gt;
&lt;p&gt;When we want to get certain text value from web element, first we execute a command that will select that web element and than we execute a command that will get the text value. That's two request being made to Selenium server. The select request doesn't actually return the web element, it only returns an id that Selenium server generated for that web element, so another request is being made to retrieve text value.&lt;/p&gt;
&lt;p&gt;Returning to our problem, that means on average we'll make 500 x 2 = 1000 requests just to select each cell and get it's text value. This of course will make the test very slow.&lt;/p&gt;
&lt;p&gt;But how can we make this test run faster? When my friend described the test case, the last step he mentioned was to verify if the report has correct data. He didn't say let's assert each cell, although that's what we must do at the end.&lt;/p&gt;
&lt;p&gt;But what if we could just make one assert in a test, one that would require us to make just one request to Selenium server? Well, we can actually do that. Just send a JavaScript that will do all data checking and return whether the report has correct data or not. It's simple as that, and if your web app uses jQuery, it's even easier.&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/4542204.js"&gt;&lt;/script&gt;
&lt;p&gt;Have an idea how to make things run faster, post a comment and we can discuss it.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/qj9SvqkjVBc" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2013/1/writing-faster-webdriver-tests</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/12/team-foundation-server-express</id><title type="text">Team Foundation Server Express</title><published>2012-12-25T23:10:00+01:00</published><updated>2012-12-25T23:10:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/wkLoxsZRvZc/team-foundation-server-express" /><content type="html">&lt;p&gt;Of all the new developer tools and&amp;nbsp;products that Microsoft launched this&amp;nbsp;fall, Team Foundation Server Express got&amp;nbsp;most of my attention. The fact that it's&amp;nbsp;free and that it comes with reasonable&amp;nbsp;limitations compared to full version,&amp;nbsp;shows that Microsoft is really dedicated&amp;nbsp;to making it's platform stronger.&lt;/p&gt;
&lt;p&gt;This blog post won't cover all the&amp;nbsp;features that are included or not, I'll&amp;nbsp;just focus on those that are most&amp;nbsp;interesting.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;What's included in the box :)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Source control - same as in full version&amp;nbsp;with history, notifications, security and&amp;nbsp;other features.&lt;/li&gt;
&lt;li&gt;Work item tracking - same as in full&amp;nbsp;version with few project templates and&amp;nbsp;ability to add new templates, customize&amp;nbsp;work items etc.&lt;/li&gt;
&lt;li&gt;Build automation - no limitations here,&amp;nbsp;you can have multiple build agents that&amp;nbsp;are on multiple machines if that's what&amp;nbsp;you need.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What's not included in the box :(&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Only supports SQL Express - sad thing&amp;nbsp;about this is that even if you have a full&amp;nbsp;SQL Server you can't use it for TFS&amp;nbsp;Express, it will install SQL Express and&amp;nbsp;use that instance.&lt;/li&gt;
&lt;li&gt;SharePoint and Reporting integration - not&amp;nbsp;sure what to say about this since I wasn't&amp;nbsp;a big fan of it and never had much fun&amp;nbsp;with it (too complicated setup).&lt;/li&gt;
&lt;li&gt;Single Server configuration - no proxies.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you're that big that you need this&amp;nbsp;feature than you should have enough funds&amp;nbsp;to purchase a full licence.&lt;br /&gt;Great thing about Visual Studio 2012&amp;nbsp;Express editions is that they now support&amp;nbsp;version control, which means that you can&amp;nbsp;use those tools with TFS Express. Also, if&amp;nbsp;you have earlier versions of Visual&amp;nbsp;Studio, TFS Express will work with them as&amp;nbsp;well and with Team Explorer Everywhere you&amp;nbsp;can use TFS Express with Eclipse.&lt;/p&gt;
&lt;p&gt;To make things clear Team Foundation&amp;nbsp;Server Express is free, but it supports up&amp;nbsp;to 5 users. Now this may seem as a deal&amp;nbsp;breaker, but if you think about it and&amp;nbsp;mind what's in the box, I think this is&amp;nbsp;quite reasonable.&lt;/p&gt;
&lt;p&gt;This version is designed for small teams,&amp;nbsp;but if you need a few more users you can&amp;nbsp;always get them by purchasing a CAL.&lt;/p&gt;
&lt;p&gt;Finally, if you ever decide to upgrade to&amp;nbsp;full TFS, the process is simple and you&amp;nbsp;won't lose any data including source&amp;nbsp;control history.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/wkLoxsZRvZc" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/12/team-foundation-server-express</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/12/disabling-google-ads</id><title type="text">Disabling Google Ads</title><published>2012-12-15T22:41:00+01:00</published><updated>2012-12-15T22:41:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/US2-OE88E8E/disabling-google-ads" /><content type="html">&lt;p&gt;Some time ago I was doing some Selenium Webdriver tests for a website with Google Ads. For QA environment the ads were &lt;span&gt;disabled&lt;/span&gt; through some website configuration, but for Staging environment&amp;nbsp;&lt;span&gt;everything&lt;/span&gt; was set up as on Live, and so the ads were enabled.&lt;/p&gt;
&lt;p&gt;However, this caused some problems when running Webdriver tests. What &lt;span&gt;happened&lt;/span&gt; is that on some pages the Webdriver would timeout because the requests made by Google Ads scripts were taking too long.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;I needed a solution to disable the Google Ads without changing the configuration of website or environment. It turned out simple, just added these two lines to hosts file on a machine where Webdriver was running and the problem was gone.&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/4299421.js"&gt;&lt;/script&gt;
&lt;p&gt;If you're running tests &lt;span&gt;locally&lt;/span&gt;, add this to your machine, and if you're using a Selenium Grid (Selenium Server), than add this on each node that will be used.&lt;/p&gt;
&lt;p&gt;You can guess what this will do. The Google ads scripts will make a request to a local host instead to Google servers, and that will cause the scripts to finish whatever they are doing, instead of making Webdriver timeout.&lt;/p&gt;
&lt;p&gt;Note that this isn't a change in website configuration or environment, these changes were made on test agent machines (client machines).&lt;/p&gt;
&lt;p&gt;Have you had this problem? How did you work around it?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/US2-OE88E8E" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/12/disabling-google-ads</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/12/switching-to-english</id><title type="text">Switching to English</title><published>2012-12-12T03:45:00+01:00</published><updated>2012-12-12T03:45:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/6TIwcFsPugY/switching-to-english" /><content type="html">&lt;p&gt;It's been more than a year and a half since I started this blog and as every blog author, I haven't written as much as I wanted, but this has been a great year so far, with a lot of great things happening at work and in my personal life and I'm not a bit sorry for not having more time to blog.&lt;/p&gt;
&lt;p&gt;So this blog post won't be about me promising that I'll blog more (or less :) it's an announcement that all future posts will be in English. This is a decision which I've made after some thinking and a lot of encouragement from friends and colleagues.&lt;/p&gt;
&lt;p&gt;Expect a real blog post soon ;) and thanks for reading.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/6TIwcFsPugY" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/12/switching-to-english</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/7/application-pool-timeout</id><title type="text">Application pool timeout usled neaktivnosti web aplikacije</title><published>2012-07-17T12:01:00+02:00</published><updated>2012-07-17T12:01:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/Y1-bNgYeJrg/application-pool-timeout" /><content type="html">&lt;p&gt;Ukoliko sajt nema posetu duže od 20 minuta, application pool će se ugasiti i osloboditi sistemske resurse. Kada sledeći zahtev dođe, IIS će automatski startovati application pool i poslati traženu starnicu.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Ovo je odoličan način da se čuvaju resursi, ali to takođe znači da prvi zahtev, onaj koji dovodi do startovanja aplikacije, je vrlo spor. Spor je zato &amp;scaron;to proces mora da se startuje, učita sve potrebne biblioteke, izvr&amp;scaron;i Application_Start metodu i na kraju procesira zahtev. U zavisnosti od veličine i složenosti aplikacije, ovo može da potraje od nekoliko sekundi do vi&amp;scaron;e od pola minuta.&lt;/p&gt;
&lt;p&gt;Podrazumevana dužina perioda neaktivnosti nakon koga dolazi do timeout-a je 20 minuta i predstavlja vreme koje worker process provede neaktivan pre nego &amp;scaron;to dođe do isključivanja aplikacije. Worker process se smatra neaktivnim ako ne obrađuje zahteve i ne primi nijedan novi zahtev.&lt;/p&gt;
&lt;p&gt;Ukoliko je potrebno da se timeout isključi u potpunosti, potrebno je setovati ga na 0, &amp;scaron;to zanči da se application pool neće nikad ugasiti ukoliko nema poseta.&lt;/p&gt;
&lt;p&gt;Svrha ove funkcionalnosti IIS-a jeste oslobađanje resursa ukoliko je aplikacija neaktivna. Ovo je posebno korisno ukoliko se na IIS serveru nalazi vi&amp;scaron;e sajtova i aplikacija, a pritom je pode&amp;scaron;eno deljenje resursa između sajtova i aplikacija.&lt;/p&gt;
&lt;p&gt;Pode&amp;scaron;avanje željene vrednosti timeout-a se može izvr&amp;scaron;iti pomoću sledeće komande:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00&lt;/pre&gt;
&lt;h2&gt;Windows Azure&lt;/h2&gt;
&lt;p&gt;Ukoliko koristite Windows Azure, da bi podesili timeout na nula, potrebno je dodati deklaraciju startup task-a u ServiceDefinition.csdef:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;Startup&amp;gt;&amp;nbsp;
    &amp;lt;Task commandLine="startup\disableTimeout.cmd" executionContext="elevated" /&amp;gt;
&amp;lt;/Startup&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Nakon toga potrebno je dodati disableTimeout.cmd u folder startup. Sadržaj ovog fajla treba da bude poziv appcmd konzoli da setuje application pool idle timeout na nula.&lt;/p&gt;
&lt;p&gt;Vi&amp;scaron;e detalja može se naći na ovoj &lt;a href="http://technet.microsoft.com/en-us/library/cc771956.aspx"&gt;adresi&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/Y1-bNgYeJrg" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/7/application-pool-timeout</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/5/gzip-i-shared-hosting</id><title type="text">GZip i shared hosting</title><published>2012-05-30T23:58:00+02:00</published><updated>2012-05-30T23:58:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/tQhT-0Jebrk/gzip-i-shared-hosting" /><content type="html">&lt;p&gt;Upotreba kompresije je svakako jedna od tehnika optimizacije web aplikacija. Ukoliko nemamo kontrolu nad IIS konfiguracijom, ili nemamo dovoljno prava, kao npr. u slučaju shared hosting re&amp;scaron;enja, možemo uključiti GZip kompresiju kroz web.config same web aplikacije.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Sve &amp;scaron;to je potrebno jeste dodati ovaj node u web.config fajl i to će uključiti GZip kompresiju za datu web aplikaciju.&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;system.webServer&amp;gt;
    &amp;lt;httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files"&amp;gt;
        &amp;lt;scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll"/&amp;gt;
        &amp;lt;dynamicTypes&amp;gt;
            &amp;lt;add mimeType="text/*" enabled="true"/&amp;gt;
            &amp;lt;add mimeType="application/javascript" enabled="true"/&amp;gt;
            &amp;lt;add mimeType="*/*" enabled="false"/&amp;gt;
        &amp;lt;/dynamicTypes&amp;gt;
        &amp;lt;staticTypes&amp;gt;
            &amp;lt;add mimeType="text/*" enabled="true"/&amp;gt;
            &amp;lt;add mimeType="application/javascript" enabled="true"/&amp;gt;
            &amp;lt;add mimeType="*/*" enabled="false"/&amp;gt;
        &amp;lt;/staticTypes&amp;gt;
    &amp;lt;/httpCompression&amp;gt;
    &amp;lt;urlCompression doStaticCompression="true" doDynamicCompression="true"/&amp;gt;
&amp;lt;/system.webServer&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Obratite pažnju da je potrebno definisati mime tipove za koje će biti omogućena, odnosno isključena kompresija.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/tQhT-0Jebrk" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/5/gzip-i-shared-hosting</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/5/selenium-2-webdriver-injection</id><title type="text">Selenium 2 WebDriver injection</title><published>2012-05-25T00:01:00+02:00</published><updated>2012-05-25T00:01:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/9G25RXs8nOk/selenium-2-webdriver-injection" /><content type="html">&lt;p&gt;Selenium 2 WebDriver ima podr&amp;scaron;ku za nekoliko browser-a:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FireFox 3.6 - 10&lt;/li&gt;
&lt;li&gt;Internet Explorer 7 - 9&lt;/li&gt;
&lt;li&gt;Opera 8 - 9&lt;/li&gt;
&lt;li&gt;Chrome&lt;/li&gt;
&lt;li&gt;itd.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kako svi drajver implementiraju IWebDriver interfejs, prirodno je da se testovi pi&amp;scaron;u kori&amp;scaron;ćenjem ovog interfejsa a ne konkretnog drajvera. Na taj način testovi će raditi sa bilo kojim internet pretraživačem. Međutim, tu se nameće problem kako instancirati konkretan drajver.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;Pode&amp;scaron;avanje Unity framework-a&lt;/h2&gt;
&lt;p&gt;Konfigurisanje DI kontejnera, odnosno registrovanje tipova možemo definisati u baznoj test klasi.&amp;nbsp;Unutar bazne test klase iskoristićemo ClassInitailize metodu za registrovanje tipova:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[TestClass]
public class BaseTestClass
{
    private static IUnityContainer container;
    public TestContext TestContext { get; set; }
    public IWebDriver Driver { get; private set; }

    [ClassInitialize]
    public static void Initialize(TestContext testContext)
    {
        container = new UnityContainer()
            .RegisterType&amp;lt;IWebDriver, FirefoxDriver&amp;gt;("Default", new InjectionConstructor())
            .RegisterType&amp;lt;IWebDriver, FirefoxDriver&amp;gt;("FireFox", new InjectionConstructor())
            .RegisterType&amp;lt;IWebDriver, ChromeDriver&amp;gt;("Chrome", new InjectionConstructor())
            .RegisterType&amp;lt;IWebDriver, InternetExplorerDriver&amp;gt;("InternetExplorer", new InjectionConstructor());
    }
}&lt;/pre&gt;
&lt;p&gt;Ova konfiguracija obezbeđuje da se pri svakom razre&amp;scaron;avanju vraća nova instanca IWebDriver-a, &amp;scaron;to je upravo ono &amp;scaron;to nam treba ukoliko želimo da pravimo testove koji su izolovani, odnosno testvi koji mogu paralelno da se izvr&amp;scaron;avaju.&lt;/p&gt;
&lt;h2&gt;Kreiranje instance IWebDriver-a&lt;/h2&gt;
&lt;p&gt;Samo kreiranje, odnosno razre&amp;scaron;avanje je najbolje implementirati na jednom mestu, u okviru TestInitialize metode bazne test klase.Najjednostavniji način da izvr&amp;scaron;imo razre&amp;scaron;avanje tipa bio bi na osnovu vrednosti konfiguracione promenljive:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[TestInitialize]
public virtual void TestInitialize()
{
    Driver = container.Resolve&amp;lt;IWebDriver&amp;gt;(Configuration.Browser);
}&lt;/pre&gt;
&lt;p&gt;U ovom primeru, Browser predstavlja string ("FireFox", "Chrome", "InternetExplorer" itd.) na osnovu koga će se izvr&amp;scaron;iti razre&amp;scaron;avanje tipa. Drugi, možda zanimljiviji način, bio bi da koristimo deo imena testa za razre&amp;scaron;avanje tipa:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[TestInitialize]
public virtual void TestInitialize()
{
    var registration = container.Registrations.Skip(1).FirstOrDefault(r =&amp;gt; TestContext.TestName.Contains(r.Name));
    Driver = container.Resolve&amp;lt;IWebDriver&amp;gt;(registration != null ? registration.Name : "Default");
}
&lt;/pre&gt;
&lt;p&gt;Evo i par testova da proverimo da li razre&amp;scaron;avanje radi kako treba:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[TestMethod]
public void Test_with_Default()
{
    Assert.IsInstanceOfType(Driver, typeof(FirefoxDriver));
}

[TestMethod]
public void Test_with_FireFox()
{
    Assert.IsInstanceOfType(Driver, typeof(FirefoxDriver));
}

[TestMethod]
public void Test_with_Chrome()
{
    Assert.IsInstanceOfType(Driver, typeof(ChromeDriver));
}

[TestMethod]
public void Test_with_InternetExplorer()
{
    Assert.IsInstanceOfType(Driver, typeof(InternetExplorerDriver));
}
&lt;/pre&gt;
&lt;p&gt;Cilj ovog posta bio je da prikaže par zanimljivih načina za instanciranje IWebDriver-a.&amp;nbsp;Svakako da ima jo&amp;scaron; načina, i vrlo rado bih čuo koji je va&amp;scaron; omiljeni način za re&amp;scaron;avanje ovog problema.&lt;/p&gt;
&lt;p&gt;Umesto implementacije neke factory klase, iskoristićemo IoC kontejner za kreiranje instance konkretnog drajvera. Za primer uzećemo Unity framework.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/9G25RXs8nOk" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/5/selenium-2-webdriver-injection</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/4/selenium-dynamic-page-object</id><title type="text">Selenium Dynamic Page Object</title><published>2012-04-11T21:54:00+02:00</published><updated>2012-04-11T21:54:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/RTGZ9N6QpuM/selenium-dynamic-page-object" /><content type="html">&lt;p&gt;O Page Object klasama sam pisao ranije u postu &lt;a href="../../../2011/11/page-object-pattern"&gt;Page Object Pattern&lt;/a&gt;, ovaj post ima za cilj da prikaže kako se može napraviti dinamička Page Object klasa. Zahvaljujući novinama koje je .Net 4.0 doneo sa sobom, pre svega dinamički tip, moguće je jednostavan način implementirati dinamički Page Object.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;Dynamic Page Object&lt;/h2&gt;
&lt;p&gt;Sve &amp;scaron;to treba jeste da na&amp;scaron;a Page Object klasa nasledi DynamicObject i da napi&amp;scaron;emo override metode TryGetMember:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class DynamicPageObject : DynamicObject
{
    private readonly IWebDriver driver;

    public DynamicPageObject(IWebDriver driver)
    {
        this.driver = driver;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        try
        {
            result = driver.FindElement(By.Id(binder.Name));
            return true;
        }
        catch (NoSuchElementException)
        {
            result = null;
            return false;
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;Ograničenje ove Page Object klase je to &amp;scaron;to se za nalaženje elemenata koristi vrednost id atributa. Kako se u praksi najče&amp;scaron;će koristi id atribut za nalaženje elemenata, ovo ograničenje retko kad predstavlja problem. Ovakvom implementacijom gubimo IntelliSense podr&amp;scaron;ku, ali zato možemo jednu instancu Page Object klase iskorititi za sve stranice u aplikaciji.&lt;/p&gt;
&lt;p&gt;Ukoliko nam je cilj da brzo napi&amp;scaron;emo Selenium testove, ova klasa može dosta u tome da pomogne. Međutim, ako planiramo veliki broj testova, investiranje u zasebne Page Object klase vi&amp;scaron;e se isplati sa aspekta održavanja testova. S druge strane, prelaz sa upotrebe Dynamic Page Object klase na zasebne Page Object klase je relativno jednostavan jer ne zavisi od logike testa.&lt;/p&gt;
&lt;h2&gt;Upotreba&lt;/h2&gt;
&lt;pre class="brush: csharp"&gt;public class Program
{
    static void Main(string[] args)
    {
        var driver = new FirefoxDriver();

        driver.Navigate().GoToUrl(@"http://www.google.com/");

        dynamic page = driver.AsDynamicPage();

        page.gbqfq.SendKeys("Ivan Franjic .Net");

        driver.Quit();
    }
}
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/RTGZ9N6QpuM" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/4/selenium-dynamic-page-object</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/3/baseless-merge</id><title type="text">Baseless merge</title><published>2012-03-12T23:27:00+01:00</published><updated>2012-03-12T23:27:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/zYiZvfuqJ9M/baseless-merge" /><content type="html">&lt;p&gt;Cilj ovog članka jeste da objasni &amp;scaron;ta je baseless merge i kako sprovesti takav merge. Razlog za&amp;scaron;to pi&amp;scaron;em ba&amp;scaron; o ovome proizliazi i toga da sam vi&amp;scaron;e puta bio u situaciji da mi se developeri, pa čak i oni sa vi&amp;scaron;e iskustva, obraćaju sa istim problemom: kako izvr&amp;scaron;iti spajanje grana koje nisu u direktnoj (roditelj-dete) vezi.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;&amp;Scaron;ta je zapravo baseless merge?&lt;/h2&gt;
&lt;p&gt;Baseless merge je proces spajanja (merging) dva fajla (ili celih foldera) koji se nalaze na granama koje nisu u direktnoj vezi.&lt;/p&gt;
&lt;p&gt;Potreba za ovakvim spajanjem grana može se javiti, na primer, ako želimo da spojimo fajlove/foldere sa dve srodne (sibling) grane, a da pri tom ne vr&amp;scaron;imo spajanje sa izvornom (roditeljskom) granom.&lt;/p&gt;
&lt;p&gt;Baseless merge, s obzirom da ne nosi dovoljno informacija o vezama izmedju fajlova/foldera, može zahtevati vi&amp;scaron;e ručnog re&amp;scaron;avanja konflikata nego prilikom običnog spajanja grana. Tako na primer, ukoliko je neki fajl preimenovan, ova operacija će se shvatiti kao brisanje fajla i dodavanje novog fajla. Zbog toga, pre svakog baseless merge-a treba dobro razmisliti da li je to stvarno potrebno ili to možemo re&amp;scaron;iti na neki drugi način.&lt;/p&gt;
&lt;h2&gt;Kako sprovesti baseless merge?&lt;/h2&gt;
&lt;p&gt;Kako potreba za sprovođenjem baseless merge-a najče&amp;scaron;će ukazuje na postojanje propusta u procesu razvoja, a pored toga ovaj proces se retko sprovodi, nije ni čudo &amp;scaron;to opcija za baseless merge nije dostupna direktno iz Visual Studio-a. Da bi sproveli baseless merge, moramo to učiniti pomoću tf console aplikacije. U tf console aplikaciji pri pozivu komande za obično spajanje grana, potrebno je dodati flag /baseless kako bi naznačili da smo svesni da grane nisu u direktnoj vezi i da ipak želimo da sprovedemo spajanje.&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/3713466.js?file=baseless.txt"&gt;&lt;/script&gt;
&lt;p&gt;Ukoliko dođe do konflikata, otvoriće se UI za re&amp;scaron;avanje konflikata, a nakon &amp;scaron;to re&amp;scaron;imo sve konflikte potrebno je uraditi checkin.&lt;/p&gt;
&lt;p&gt;Vi&amp;scaron;e informacija o merge komandi možete videti na &lt;a href="http://msdn.microsoft.com/en-us/library/bd6dxhfy.aspx"&gt;MSDN&lt;/a&gt;-u.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/zYiZvfuqJ9M" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/3/baseless-merge</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/2/skrivanje-interfejsa-klasa-i-metoda</id><title type="text">Skrivanje interfejsa, klasa i metoda</title><published>2012-02-27T22:27:00+01:00</published><updated>2012-02-27T22:27:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/CCXa6JitOBQ/skrivanje-interfejsa-klasa-i-metoda" /><content type="html">&lt;p&gt;Sigurno ste nekom prilikom napravili biblioteku na koju ste bili ponosni, a onda totalno razočarani pretrpanim IntelliSense-om kada poku&amp;scaron;ate da je koristite. Veliki broj interfejsa, klasa ili metoda čine va&amp;scaron;u biblioteku te&amp;scaron;kom za kori&amp;scaron;ćenje. Pravilnom upotrebom modifikatora pristupa ovaj problem se može samo delimično sanirati, jer neki tipovi jednostavno moraju biti javni. Ovaj problem je naročito očigledan ako ste pravili biblioteku koja izlaže fluent API.&lt;/p&gt;
&lt;p&gt;Na svu sreću postoji jedan atribut u okviru System.ComponentModel namespace-a koji nam može u ovome pomoći.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;EditorBrowsableAttribute klasa&lt;/h2&gt;
&lt;p&gt;Ovim atributom mogu se dekorisati gotovo svi elementi aplikacije, osim asemblija, modula, parametra, genričkog parametra i povratne vrednosti. A pomoću State property-ja defini&amp;scaron;e se vidiljivost elementa koji je dekorisan atributom. Skrivanje se vr&amp;scaron;i samo na nivou IntelliSense-a, odnosno, svi skriveni elementi su i dalje dostupni ali se ne vide u IntelliSense-u.&lt;/p&gt;
&lt;h2&gt;Primer&lt;/h2&gt;
&lt;p&gt;S obzirom da sve korisničke klase imaju kao bazni Object klasu, kada kreiramo korisničku klasu, bez ijedne metode, imaćemo pristup dobro poznatim metodama Equals, GetHashCode, GetType i ToString. Ukoliko ove metode namaju smisla u kontekstu biblioteke koju pravimo, možemo ih sakriti i na taj način smanjiti listu metoda u IntelliSense-u.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[EditorBrowsable(EditorBrowsableState.Never)]
public interface IHidden
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    bool Equals(object obj);

    [EditorBrowsable(EditorBrowsableState.Never)]
    int GetHashCode();

    [EditorBrowsable(EditorBrowsableState.Never)]
    Type GetType();

    [EditorBrowsable(EditorBrowsableState.Never)]
    string ToString();
}

public class MyClass : IHidden
{
    public void DoSomething()
    {
        // some implementation
    }

    public void DoSomethingElse()
    {
        // some other implementation
    }
}
&lt;/pre&gt;
&lt;p&gt;Atribut nad samim interfejsom obezbeđuje da sam interfejs ne bude izlistan kada listamo namespace u kome se nalazi, dok atribut nad metodama Equals, GetHashCode, GetType i ToString skriva ove metode kada pristupamo članicama MyClass kalse.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/CCXa6JitOBQ" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/2/skrivanje-interfejsa-klasa-i-metoda</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/2/migracija-sa-selenium-rc-na-selenium-webdriver</id><title type="text">Migracija sa Selenium RC na Selenium WebDriver</title><published>2012-02-14T09:28:00+01:00</published><updated>2012-02-14T09:28:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/JlheBlvrInk/migracija-sa-selenium-rc-na-selenium-webdriver" /><content type="html">&lt;p&gt;Kako je WebDriver naslednik Selenium RC-a, svakako da je bolja investicija pisati nove testove kori&amp;scaron;ćenjem novog API-ja. Međutim, &amp;scaron;ta raditi sa testovima koji već postoje i koji su napisani za Selenium RC. Tvorci WebDriver-a su ovaj problem imali u vidu i zbog toga je moguće izvr&amp;scaron;iti migraciju na novi API na prilično bezbolan način.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Ukoliko je Selenium Server već startovan, potrebno je dodati u test jo&amp;scaron; dve linije koda:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;var selenium = new DefaultSelenium("localhost", 4444, "*firefox", "http://www.google.com");
selenium.Start();&lt;/pre&gt;
&lt;p&gt;Eto toliko je jednostavno :)&lt;/p&gt;
&lt;h2&gt;A za&amp;scaron;to bi pre&amp;scaron;li na WebDriver?&lt;/h2&gt;
&lt;p&gt;WebDriver bolje opona&amp;scaron;a korisničke akcije.&amp;nbsp;Za razliku od Selenium RC-a koji koristi JavaScript za automatizaciju, WebDriver se oslanja na ugrađenu podr&amp;scaron;ku za automatizaciju.&amp;nbsp;Ovo je moguće zbog toga &amp;scaron;to u razvoju WebDriver framework-a aktivno učestvuju i proizvođači pretraživača, kao &amp;scaron;to su Opera, Mozilla i Google.&amp;nbsp;Drugim rečima, podr&amp;scaron;ka za WebDriver se ugrađuje direktno u pretraživač, &amp;scaron;to doprinosi brzini i stabilnosti.&amp;nbsp;Na kraju, WebDriver ima manji API &amp;scaron;to ga čini lak&amp;scaron;im za učenje, ali to nikako ne znači da ima manje mogućnosti.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/JlheBlvrInk" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/2/migracija-sa-selenium-rc-na-selenium-webdriver</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/1/generic-controller</id><title type="text">Generic Controller</title><published>2012-01-30T22:38:00+01:00</published><updated>2012-01-30T22:38:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/zLaugmofD3Y/generic-controller" /><content type="html">&lt;p&gt;Kao nastavak na prethodni članak, ovde je opisan jedan od načina realizacije generičkog re&amp;scaron;enja za kontrolere. Ono &amp;scaron;to je zajedničko za većinu kontrolera jeste da sadrže CRUD (Create, Read, Update, Delete) operacije. Međutim, kontroleri se oslanjaju na različite Repository implementacije i manipuli&amp;scaron;u različitim entitetima. Zbog toga je logično napraviti neku baznu klasu koja obuhvata CRUD operacija ali je ujedno i generička kako bi mogla da radi sa različitim entitetima. Ovaj članak se nadovezuje na prethodni - &lt;a href="../../2012/1/generic-repository"&gt;Generic Repository&lt;/a&gt;, tako da je preporučljivo prethodno pročitati i taj članak.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;Generic Controller&lt;/h2&gt;
&lt;p&gt;Generički kontroler je namerno definisan kao apstraktna klasa, a sve metode kao virtuelne kako bi morali da kreiramo konkretan kontroler za svaki od entiteta i ukoliko je potrebno kreiramo override virtuelne metode.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public abstract class GenericController&amp;lt;TModel, TRepository&amp;gt; : Controller where TModel : EntityObject, new() where TRepository : IRepository&amp;lt;TModel&amp;gt;
{
    protected TRepository db;

    protected GenericController(IRepository&amp;lt;TModel&amp;gt; repository)
    {
        this.db = (TRepository)repository;
    }

    public virtual ActionResult Index()
    {
        var entities = this.db.All();
        return View(entities);
    }

    public virtual ActionResult Create()
    {
        return View(new TModel());
    }

    [HttpPost]
    public virtual ActionResult Create(TModel entity)
    {
        if (ModelState.IsValid)
        {
            this.db.Add(entity);
            TempData["Success"] = string.Format("New {0} successfully created.", entity.GetType().Name);
            return RedirectToAction("Index");
        }
        else
        {
            TempData["Error"] = string.Format("Unable to create new {0}.", entity.GetType().Name);
            View(entity);
        }
    }

    public virtual ActionResult Edit(int id)
    {
        var entity = this.db.Get(id);
        return View(entity);
    }

    [HttpPost]
    public virtual ActionResult Edit(TModel entity)
    {
        if (ModelState.IsValid)
        {
            this.db.Update(entity);
            TempData["Success"] = string.Format("{0} successfully updated.", entity.GetType().Name);&amp;amp;
            return RedirectToAction("Index");
        }
        else
        {
            TempData["Error"] = string.Format("Unable to update {0}.", entity.GetType().Name);
            return View(entity);
        }
    }

    public virtual ActionResult Delete(int id)
    {
        var entity = this.db.Get(id);
        return View(entity);
    }

    [HttpPost]
    public virtual ActionResult Delete(TModel entity)
    {
        this.db.Delete(entity);
        TempData["Success"] = string.Format("{0} successfully deleted.", entity.GetType().Name);
        return RedirectToAction("Index");
    }
}
&lt;/pre&gt;
&lt;h2&gt;CateogryController&lt;/h2&gt;
&lt;p&gt;CateogryController predstavlja konkretan kontroler za Category entitet. Ukoliko su nam dovoljne metode generičkog kontrolera dovoljno je samo definisati konstruktor. Ako se pitate za&amp;scaron;to parametarski konsturktor, svrha toga jeste da se omogući &lt;a href="../../2011/5/dependency-injection"&gt;DI&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class CategoryController : GenericController&amp;lt;Category, CategoryRepository&amp;gt;
{
    public CategoryController(IRepository&amp;lt;Category&amp;gt; repository)
        : base(repository)
    {
    }

    [HttpPost]
    public override ActionResult Delete(Category category)
    {
        //Performe some logic
        return base.Delete(category);
    }
}
&lt;/pre&gt;
&lt;p&gt;Ukoliko postoji razlika u logici nekog od generičkih metoda možemo jednostavno da napi&amp;scaron;emo override te metode kao &amp;scaron;to je to urađeno se Delete(Category category) metodom.&lt;/p&gt;
&lt;h2&gt;Korak dalje&lt;/h2&gt;
&lt;p&gt;Ukoliko su nam dovoljne samo metode definisane u GenericController klasi, i ukoliko smatramo da neće biti potrebe za override-ovanjem tih metoda možemo otići korak dalje i kreirati kontroler u run-time-u. Da bi to bilo moguće potrebno je da uradimo dve stvari. Pre svega, potrebno je da GenericController bude konkretna a ne apstraktna klasa kao u primeru gore. A zatim je potrebno kreirati custom ControllerFactory sa sledećom implementacijom CreateController metode:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public IController CreateController(RequestContext requestContext, string controllerName)
{
    Type controllerType = Type.GetType("GenericController").MakeGenericType(Type.GetType(controllerName), Type.GetType(controllerName + "Repository"));
    return Activator.CreateInstance(controllerType) as IController;
}&lt;/pre&gt;
&lt;p&gt;Activator će kreirati GenericController&amp;lt;controllerName, controllerName + "Repository"&amp;gt;, gde je controllerName isto &amp;scaron;to i ime entiteta. Drugim rečima umesto CategoryController kao iz primera sa početka posta, dobićemo GenericController&amp;lt;Category, CaterogyRepository&amp;gt;. Na ovaj način bi se oslobodili potrebe da kodiramo konkretan kontroler za svaki od entiteta.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/zLaugmofD3Y" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/1/generic-controller</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2012/1/generic-repository</id><title type="text">Generic Repository</title><published>2012-01-17T22:28:00+01:00</published><updated>2012-01-17T22:28:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/rJ8d-T07Ejs/generic-repository" /><content type="html">&lt;p&gt;U ASP.NET MVC zajednici jako je popularna upotreba Repository paterna za rad sa podacima, zbog toga gotovo da ne postoje primeri koji se ne oslanjaju na ovaj patern. Vi&amp;scaron;e informacija o Reposiotry paternu može se naći na &lt;a href="http://msdn.microsoft.com/en-us/library/ff649690.aspx"&gt;MSDN&lt;/a&gt;-u ili na sajtu &lt;a href="http://martinfowler.com/eaaCatalog/repository.html"&gt;Martin-a Fowler-a&lt;/a&gt;, a u ovom postu je prikazan kod koji ilustruje kako može da se implementira generički Repository nad Entity Framework-om.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;IRepository&amp;lt;T&amp;gt;&lt;/h2&gt;
&lt;p&gt;Ovaj generički interfejs defini&amp;scaron;e metode koje zahtevaju sve konkretne Repository klase.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public interface IRepository&amp;lt;T&amp;gt; where T : class
{
    IQueryable&amp;lt;T&amp;gt; All();
    IQueryable&amp;lt;T&amp;gt; GetAll(Func&amp;lt;T, bool&amp;gt; exp);
    T Get(Func&amp;lt;T, bool&amp;gt; exp);
    T Get(int id);
    void Add(T entity);
    void Update(T entity);
    void Delete(int id);
}
&lt;/pre&gt;
&lt;h2&gt;EntityRepository&amp;lt;T&amp;gt;&lt;/h2&gt;
&lt;p&gt;EntityRepository predstavlja baznu klasu za sve konkretne Repository klase, implementira IRepository interfejs i dodaje jednu apstraktnu metodu - Map(T entity). Ovu metodu je potrebno implementirati u konkretnoj Repository klasi, &amp;scaron;to ćemo kasnije i videti, i namerno je uvedena jer se u praksi pokazalo da često ne želimo da dozvolimo ažuriranje svih propertija entiteta.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public abstract class EntityRepository&amp;lt;T&amp;gt; : IRepository&amp;lt;T&amp;gt; where T : EntityObject
{
    protected MyEntities db;
    private string entityKeyName;
    private ObjectSet&amp;lt;T&amp;gt; entitySet;

    protected EntityRepository(MyEntities context)
    {
        this.db = context;
        this.entitySet = this.db.CreateObjectSet&amp;lt;T&amp;gt;();
        // only simple keys are supported!
        this.entityKeyName = this.entitySet.EntitySet.ElementType.KeyMembers[0].Name;
    }

    protected abstract void Map(T entity);

    public virtual IQueryable&amp;lt;T&amp;gt; All()
    {
        return this.entitySet;
    }

    public virtual IQueryable&amp;lt;T&amp;gt; GetAll(Func&amp;lt;T, bool&amp;gt; exp)
    {
        return this.entitySet.Where(exp).AsQueryable&amp;lt;T&amp;gt;();
    }

    public virtual T Get(Func&amp;lt;T, bool&amp;gt; exp)
    {
        return this.entitySet.SingleOrDefault&amp;lt;T&amp;gt;(exp);
    }

    public virtual T Get(int id)
    {
        var itemParameter = Expression.Parameter(typeof(T), "item");
        var binaryExpression = Expression.Equal(
                Expression.Property(itemParameter, this.entityKeyName),
                Expression.Constant(id));
        var expression = Expression.Lambda&amp;lt;Func&amp;lt;T, bool&amp;gt;&amp;gt;(binaryExpression, new[] { itemParameter });
        return Get(expression.Compile());
    }

    public virtual void Add(T entity)
    {
        this.entitySet.AddObject(entity);
        this.db.SaveChanges();
    }
    
    public virtual void Update(T entity)
    {
        Map(entity);
        this.db.SaveChanges();
    }

    public virtual void Delete(int id)
    {
        this.entitySet.DeleteObject(Get(id));
        this.db.SaveChanges();
    }
}
&lt;/pre&gt;
&lt;p&gt;Get metoda možda deluje zastra&amp;scaron;ujuće ali zapravo radi vrlo jednostavnu stvar - kreira lambda izraz na osnovu koga će se filtrirati Repository. Na primer, ako imamo entitet Category koji ima primarni ključ CategoryId, izraz koji će se generisati je item =&amp;gt; item.CategoryId == id, gde id ima neku konkretnu vrednost.&lt;/p&gt;
&lt;p&gt;Očigledna prednost ovakvog generičkog dizajna je u tome &amp;scaron;to nam omogućava upotrebu ovog koda za bilo koji projekat. S druge strane, mana je to &amp;scaron;to se neke stvari podrazumevaju, odnosno zasniva se na konvenciji. Na primer, podrazumeva da svi entiteti imaju prost primarni ključ. Ako pogledamo malo bolje Get metodu u kojoj se kreira lambda izraz, može se primetiti da se koristi samo jedan parametar kao naziv ključa.&lt;/p&gt;
&lt;p&gt;Naravno, moguće je implementirati kreiranje izraza koji sadrži i složeni ključ ali to pored usložnjavanja utiče i na performanse metode. Ovde je namerno izabrana pomenuta konvencija jer je to sasvim dovljno za jednostavne web aplikacije.&lt;/p&gt;
&lt;h2&gt;CategoryRepository&lt;/h2&gt;
&lt;p&gt;Za primer konkretne Repository klase uzećemo Repository koji radi sa Category entitetima.&amp;nbsp;CategoryRepository nasleđuje baznu EntityRepository klasu i implementira apstraktnu Map metodu.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class CategoryRepository : EntityRepository&amp;lt;Category&amp;gt;
{
    public CategoryRepository(MyEntities context)
        : base(context)
    {
    }

    protected override void Map(Category original, Category entity)
    {
        original.Name = entity.Name;
        original.Description = entity.Description;
        original.Modefied = entity.Modefied;
    }
}
&lt;/pre&gt;
&lt;p&gt;Category entitet sadrži jo&amp;scaron; neke propertije koje ne želimo da ažuriramo (npr. Created) i upravo je zbog toga potrebno implementirati Map metodu koja će ažurirati samo željene propertije.&lt;/p&gt;
&lt;p&gt;Na kraju, da pomenem da se ova implementacija oslanja na Entity Framework (Model first), te da ukoliko bi koristili EF Code first pristup imali bi i jednostavniju implementaciju.Eto ne&amp;scaron;to o čemu možete da razmi&amp;scaron;ljate :)&lt;/p&gt;
&lt;p&gt;Sledećom prilikom ćemo se pozabaviti generičkim kontrolerom koji se oslanja na ovaj generički Repository.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/rJ8d-T07Ejs" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2012/1/generic-repository</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/12/webdriver-itakescreenshot</id><title type="text">WebDriver - ITakeScreenshot</title><published>2011-12-15T22:19:00+01:00</published><updated>2011-12-15T22:19:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/pvUpA1CXb7M/webdriver-itakescreenshot" /><content type="html">&lt;p&gt;Prilikom izvr&amp;scaron;avanja auto testa često sam bio u situaciji da mi je potreban screenshot aplikacije. Razloga za to može biti vi&amp;scaron;e, ali najče&amp;scaron;ći razlog jeste potreba da se uhvati trenutak u kome je test pao kako bi se lak&amp;scaron;e utvrdio uzrok.&lt;/p&gt;
&lt;p&gt;Pored toga neke stvari je neophodno testirati, ali samo testiranje nije moguće u potpunosti automatizovati. Na primer, potrebno je testirati da li je layout ili uop&amp;scaron;te neki vizuelni aspekt aplikacije korektan.&lt;/p&gt;
&lt;p&gt;Koji god razlog da je, pomouću Selenium 2 WebDriver-a moguće je napraviti screenshot internet pretraživača na vrlo jednostavan način.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Primer koji sledi prikazuje kako se može uhvatiti screenshot ukoliko test padne:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[TestClass]
public class MyTests
{
    public TestContext TestContext { get; set; }
    public IWebDriver Driver { get; private set; }
    
    /// &amp;lt;summary&amp;gt;
    /// Test initialize
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;remarks&amp;gt;This method is run before each Test&amp;lt;/remarks&amp;gt;
    [TestInitialize]
    public void TestInitialize()
    {
        Driver = new FirefoxDriver();
    }

    /// &amp;lt;summary&amp;gt;
    /// Test cleanup
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;remarks&amp;gt;This method is run after each Test&amp;lt;/remarks&amp;gt;
    [TestCleanup]
    public void TestCleanup()
    {
        var screenShotDriver = Driver as ITakesScreenshot;
        if (screenShotDriver == null) return;

        // Make filename unique in case this is a cleanup for data-driven test ;)
        var filename = string.Format("screenshot-{0}.png", DateTime.Now.Ticks);
        var fullFilename = Path.Combine(TestContext.ResultsDirectory, filename);
        
        var screenShot = screenShotDriver.GetScreenshot();
        screenShot.SaveAsFile(fullFilename, ImageFormat.Png);
        TestContext.AddResultFile(fullFilename);
        
        Driver.Quit();
    }

    [TestMethod]
    public void ScreenshotTest()
    {
        Assert.Fail("I just want to take a screenshot!");
    }
}
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/pvUpA1CXb7M" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/12/webdriver-itakescreenshot</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/12/pagemapper</id><title type="text">PageMapper</title><published>2011-12-03T19:53:00+01:00</published><updated>2011-12-03T19:53:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/vkKmn3bBVEU/pagemapper" /><content type="html">&lt;p&gt;U prethodnom postu sam govorio o &lt;a href="../../2011/11/page-object-pattern"&gt;Page Object paternu&lt;/a&gt; kao načinu pisanja UI testova i dao primer koji se oslanja na Selenium WebDriver. Iako ovaj pristup smanjuje dupliranje koda i olak&amp;scaron;ava održavanje, implementacija Page Object klasa može da bude prilično zamorna.&lt;/p&gt;
&lt;p&gt;Da bi koristli Paga Object kalse, potrebno je da izvr&amp;scaron;imo mapiranje korisničkog interfejsa aplikacije koja se testira. Ako uzmemo u obzir da jedna netrivijalna aplikacija može da ima nekoliko desetina, pa i par stotina, stranica a da pri tom svaka stranica može da ima veći broj UI kontrola koje podržavaju neki vid interakcija, jasno je da UI mapiranje može da preraste u veliki posao.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Kako bih donekle ublažio ovaj bolni proces, napravio sam jednostavan alat za mapiranje web stranica. PageMapper je inicijalno planiran kao alat koji treba da mapira web stranice za Selenium WebDriver C# biblioteku. Međutim, kako alat koristi &lt;a href="http://razorengine.codeplex.com/"&gt;Razor&lt;/a&gt; za generisanje Page Object klase, dodavanjem novih templejta mogu se generisati i klase za druge programske jezike, pa čak i za druge framework-e za UI testiranje.&lt;/p&gt;
&lt;p&gt;Podrazumevani templejt generi&amp;scaron;e stranicu koja se oslanja na &lt;a href="http://code.google.com/p/selenium/wiki/PageFactory"&gt;PageFactory&lt;/a&gt; klasu, iz WebDriver Support biblioteke, za kreiranje Page Object-a. Naravno, plan je da se dodaju i templejti za ostale jezike, pa ako želite da doprinesete slobodno mi se javite.&lt;/p&gt;
&lt;p&gt;Pre nego &amp;scaron;to skinete ovaj alat treba da znate da je jo&amp;scaron; uvek u razvoju. Trenutna verzija je 0.9, i iako je funkcionalna, nedostaju neke stvari kao &amp;scaron;to su validacija i error logging. Međutim, uz pravilnu upotrebu alat neće praviti nikakve probleme :)&lt;/p&gt;
&lt;p&gt;Nemojte se iznenaditi ako se otvore dve forme kada pokrenete alat. Nakon demo verzije, koja je imala jednu formu, shvatio sam da mi je jedna forma suvi&amp;scaron;e mala. Tako je nova verzija alat osmi&amp;scaron;ljena da se koristi sa dva monitora, gde bi na jednom monirotu bila browser forma a glavna forma na drugom.&lt;/p&gt;
&lt;p&gt;Browser forma se koristi za navigaciju kroz web sajt čije stranice treba da se mapiraju, a da bi se izvr&amp;scaron;ila selekcija nekog UI elemnta potrebno je držati CRTL i mi&amp;scaron;em preći preko željenog UI elemnta. Na glavnoj formi se prikazuju informacije o selektovanom elementu, koji nakon toga možemo dodati u listu. Svi web elementi koji se nalaze u listi biće generisani kako propertiji Page Object klase.&lt;/p&gt;
&lt;p&gt;Za sva pitanja ili sugestije u vezi alata možete me slobodno kontaktirati.&lt;/p&gt;
&lt;p&gt;BitBucket: &lt;a href="https://bitbucket.org/frennky/pagemapper"&gt;PageMapper&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/vkKmn3bBVEU" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/12/pagemapper</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/11/page-object-pattern</id><title type="text">Page Object Pattern</title><published>2011-11-30T23:03:00+01:00</published><updated>2011-11-30T23:03:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/doqQKVO7huo/page-object-pattern" /><content type="html">&lt;p&gt;Od testova se očekuje da se brzo prilagode promenama korisničkog interfejsa, koje su nažalost vrlo česte. Pored toga, od testova se očekuje da rade sa vi&amp;scaron;e različitih korisničkih interfejsa za različite uređaje, počev od web stranica za desktop browser-e pa do mobilnih verzija stranica za mobile browser-e.&lt;/p&gt;
&lt;p&gt;Za ove probleme postoji univerzalno re&amp;scaron;enje u vidu Page Object paterna koji se može primeniti kako na web tako i na desktop aplikacije, odnosno na bilo koju vrstu GUI aplikacija.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;&amp;Scaron;ta je Page Object patern?&lt;/h2&gt;
&lt;p&gt;Su&amp;scaron;tina Page Object paterna jeste u mapiranju UI strane na Page klasu, gde strana može biti HTML strana, WPF forma i sl. Korisničke akcije nad UI stranom se izlažu kroz metode, a sami UI elementi kroz propertije Page klase. Na taj način dobija se jedan sloj između samog testa i aplikacije koja se testira, a posledica svega toga je lak&amp;scaron;e kreiranje novih testova i održavanje test koda kada dođe do promena na aplikaciji.&lt;/p&gt;
&lt;p&gt;Kada govorimo o automatskom testiranju, stranica ne predstavlja ni&amp;scaron;ta vi&amp;scaron;e do strane koju korisnik vidi. Svaka stranica se sastoji od proizvoljnog broja različitih komponenti, od kojih neki samo prikazuju podatke (npr. labele), dok drugi obezbeđuju interakciju (npr. dugmići). Stranice, međutim, mogu imati neki zajednički sadržaj kao &amp;scaron;to su zaglavlja, polja za pretragu ili menije.&lt;/p&gt;
&lt;p&gt;Upotreba Page klasa bi trebalo da obezbedi lak&amp;scaron;u izmenu testova ukoliko dođe do promene aplikacije koja se testira, jer je potrebno napraviti izmenu samo na jednom mestu. Pored toga, kreiranje i održavanje testova je znatno lak&amp;scaron;e, jer sadrže samo logiku koja je potrebna za test.&lt;/p&gt;
&lt;p&gt;Ovaj patern nije vezan isključivo za web aplikacije, ali ću iskoristiti priliku da ga objasnim i prikažem kroz primer koji se oslanja na Selenium WebDriver.&lt;/p&gt;
&lt;h2&gt;Selenium WebDriver PageFactory&lt;/h2&gt;
&lt;p&gt;Implementacija ovog paterna podrazumeva kreiranje klase, sa odgovarajućim metodama, za svaku stranicu ili deo stranice (zaglavlje, meni itd.) aplikacije koja se testira. Metode ovih klasa treba da odgovaraju akcijama koje se izvr&amp;scaron;avaju nad stranicama. Takođe, klase treba da sadrže propertije za UI elemente sa kojima korisnik ima interakciju.&lt;/p&gt;
&lt;p&gt;Za podr&amp;scaron;ku Page Object paterna u okviru WebDriver Support biblioteke postoji klasa &lt;a href="http://code.google.com/p/selenium/wiki/PageFactory"&gt;PageFactory&lt;/a&gt;. Jednostavan primer, sličan primeru iz prethodnog posta, bi izgledao ovako:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;

namespace Tests.Pages
{
    public class GoogleHomePage
    {
        private string url = "http://www.google.com/";
        private IWebDriver driver;

        [FindsBy(How = How.Name, Using = "q")]
        public IWebElement QueryTextBox { get; set; }

        [FindsBy(How = How.Name, Using = "btnK")]
        public IWebElement SearchButton { get; set; }

        public GoogleHomePage(IWebDriver webDriver)
        {
            driver = webDriver;
            PageFactory.InitElements(driver, this);
        }

        public void Navigate()
        {
            driver.Navigate().GoToUrl(url);
        }
    }
}

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Tests.Pages;
using OpenQA.Selenium.Firefox;

namespace Tests
{
    [TestClass]
    public class GoogleTests
    {
        [TestMethod]
        public void Test1()
        {
            var driver = new FirefoxDriver();

            var googleHomePage = new GoogleHomePage(driver);

            googleHomePage.QueryTextBox.SendKeys("Ivan Franjic .Net");

            googleHomePage.SearchButton.Click();

            Assert.IsTrue(driver.Title.Contains("Ivan Franjic .Net"));

            driver.Quit();
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;Treba napomenuti da se WebElement-i instanciraju po pozivu. Odnosno, ukoliko se nekom WebElement-u Page Object klase nikad ne pristupi, nikad se neće pozvati "FindElement" za taj WebElement.&lt;/p&gt;
&lt;p&gt;S obzirom da stranica enkapsulira specifičnosti test framework-a (u ovom slučaju Selenium WebDriver), ako promenimo ovaj test framework potrebno je samo implementirati Page klase dok logika testa ostaje netaknuta. Dakle, dolazimo do toga da se izlažu stvari koje mogu da se vide i urade na stranici, a skrivaju detalji kako se to zapravo izvodi. Takođe, sa Page klasama je jasno gde se može naći postojeći i gde staviti novi kod.&lt;/p&gt;
&lt;p&gt;Na kraju, može se izvesti zaključak da ovakav način pisanja test koda promovi&amp;scaron;e upotrebljivost i smanjuje dupliranje koda čineći testove čitljivijim, &amp;scaron;to naravno pobolj&amp;scaron;ava održavanje naročito u situacijama kada se aplikacija brzo razvija.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/doqQKVO7huo" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/11/page-object-pattern</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/11/selenium-2-webdriver</id><title type="text">Selenium 2 - WebDriver</title><published>2011-11-18T22:39:00+01:00</published><updated>2011-11-18T22:39:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/MSKEyaPAPdo/selenium-2-webdriver" /><content type="html">&lt;p&gt;Selenium 2 (WebDriver) pretstavlja jedno od re&amp;scaron;enja za automatsko testiranje web aplikacija. Ima jednostavan API koji se brzo i lako uči, svakako lak&amp;scaron;e nego Selenium-RC (1.0) API, &amp;scaron;to naravno čini testove lak&amp;scaron;im za razumevanje i održavanje. Ne zavisi ni od jednog test framework-a tako da se može se koristiti uz bilo koji unit testing framework (NUnit, xUnit, MSTest itd.).&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;Kako to zapravo radi&lt;/h2&gt;
&lt;p&gt;Kada se jednom doda u test projekat, WebDriver se koristi kao i bilo koja druga biblioteka i za razliku od Selenium RC nisu potrebne nikakve dodatne instalacije ili startovanje dodatnih procesa. WebDriver radi tako &amp;scaron;to direktno komunicira sa internet pretraživačem koristeći podr&amp;scaron;ku za automatizaciju koja je ugrađena u sam internet pretraživač (da dobro ste pročitali dana&amp;scaron;nji pretraživači imaju ugrađenu podr&amp;scaron;ku za automatizaciju).&lt;/p&gt;
&lt;p&gt;Za razliku od WebDriver-a, Selenium-RC se oslanjao na Selenium Server koji je ubacivao javascript u internet pretraživač kako bi ga automatizovao. Dakle, testovi su bili pisani u nekoj klijentskoj Selenium biblioteci, a zatim su se te komande prevodile u javascript. Na svu sreću, od kad su se proizvođači internet pretraživača uključili u celu priču, stvari su postale dosta jednostavnije.&lt;/p&gt;
&lt;h2&gt;Kako početi&lt;/h2&gt;
&lt;p&gt;Preko &lt;a href="http://www.nuget.org/"&gt;NuGet&lt;/a&gt; servisa može se brzo i jednostavno skinuti najnovija verzija &lt;a href="http://www.nuget.org/List/Packages/Selenium.WebDriver"&gt;WebDriver&lt;/a&gt; biblioteke. Pored osnovne biblioteke preko NuGet servisa može da se skine i Support biblioteka, o kojoj ću nekom drugom prilikom vi&amp;scaron;e pisati.&lt;/p&gt;
&lt;p&gt;Ovo vam je dovoljno da možete da počnete da pi&amp;scaron;ete auto testove za FireFox i InternetExplorer. Za Chrome vam treba driver koji može &lt;a href="http://code.google.com/p/chromium/downloads/list"&gt;ovde&lt;/a&gt; da se skine.&lt;/p&gt;
&lt;h2&gt;Primer&lt;/h2&gt;
&lt;p&gt;U ovom primeru se koristi MSTest kao testni framework, ali naravno može se koristiti i bilo koji drugi. Nadam se da ćete posle ovog primera uvideti kako je jednostavno pisati auto testove pomoću Selenium WebDriver biblioteke.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;using OpenQA.Selenium.Firefox;
using OpenQA.Selenium;

[TestClass]
public class GoogleTest
{
    [TestMethod]
    public void Test1()
    {
        IWebDriver driver = new FirefoxDriver();

        driver.Navigate().GoToUrl("http://www.google.com/");

        IWebElement query = driver.FindElement(By.Name("q"));
        query.SendKeys("Ivan Franjic .Net");

        IWebElement resultLink = driver.FindElement(By.PartialLinkText("ivanfranjic.net"));
        resultLink.Click();
        
        Assert.IsTrue(driver.Title.Contains("Ivan Franjic Blog"), "Ooops, wrong blog opened.");
        driver.Quit();
    }
}
&lt;/pre&gt;
&lt;p&gt;Toliko za sad, vidimo se uskoro :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/MSKEyaPAPdo" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/11/selenium-2-webdriver</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/11/testiranje-web-a</id><title type="text">Testiranje web-a</title><published>2011-11-14T10:53:00+01:00</published><updated>2011-11-14T10:53:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/49wOKkJ0YGI/testiranje-web-a" /><content type="html">&lt;p&gt;Problemi koji postoje u automatskom testiranju web aplikacija su slični problemima pri testiranju desktop aplikacija. Kod web aplikacija imamo različite internet pretraživače kao i različite verzije pretraživača. S druge strane, kod desktop aplikacija imamo različite platforme (Delphi, Java, .Net), a postoje i značajne razlike u pristupu automatizaciji u zavisnosti od UI framework-a (kao npr. Win32, WinForms, WPF). Zbog toga retko koji framework za testiranje UI-a podržava vi&amp;scaron;e različitih platformi ili pretraživača.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Pre par godina imao sam prvi put priliku da se oprobam u testiranju web aplikacija. Do data sam već imao dobrog iskustva u testiranju desktop aplikacija. Kako smo za svoje potrebe kreirali framework za testiranje WinForms i Delphi aplikacija, znao sam dobro koliko je to veliki posao. Zbog toga sam prvo konsultovao Google kako bih saznao da li postoji neki framework za web automatizaciju.&lt;/p&gt;
&lt;p&gt;Nažalost u to vreme open source nije nudio mnogo re&amp;scaron;enja. Među nekoliko re&amp;scaron;enja, istakli su se Selenium RC i WatiN. Međutim, Selenium smo odbacili iz ne sećam se kojih razloga, dok je WatiN bio jo&amp;scaron; uvek na početku razvoja. Na kraju smo ipak odlučili da napravimo sopstveno lightweight re&amp;scaron;enje. Sve &amp;scaron;to je bilo potrebno jeste da se domognemo DOM-a, a posle je sve i&amp;scaron;lo lako. Framework koji smo kreirali se oslanjao na &lt;a href="http://msdn.microsoft.com/en-us/library/aa741312.aspx"&gt;mshtml&lt;/a&gt; biblioteku i podržavao je automatizaciju Internet Explorer-a.&lt;/p&gt;
&lt;p&gt;Posle nekog vremena pre&amp;scaron;ao sam da radim na auto testovima za WPF aplikacije, a na&amp;scaron; web framework je ostao zaboravljen. Od tada je pro&amp;scaron;lo dosta vremena, a ja sam opet dobio priliku da radim na autotestovima za web aplikacije.&lt;/p&gt;
&lt;p&gt;Po pitanju framework-a za testiranje web-a, situacija je danas znatno bolja. WatiN je prilično zreo framework, sadrži apstrakcije UI kontrola i stranica, tako da prirodno podržava Page pattern.&lt;/p&gt;
&lt;p&gt;S druge strane, Selenium je pretrpeo znatnu izmenu u API-ju sa novom verzijom. Selenium 2, ili kako ga jo&amp;scaron; zovu WebDriver, ima mali i vrlo jednostavan API tako da se vrlo brzo uči. Za Selenium WebDriver postoji pomoćna biblioteka koja omugćava kreiranje Page objekata, odnosno primenu Page paterna.&lt;/p&gt;
&lt;p&gt;Iako WatiN možda bolje koristi mogućnosti C# jezika, ipak se Selenium WebDriver pokazao prijatniji za rad. Pored toga, ne treba zaboraviti da Selenium ima prilično veliku zajednicu, kao i da podržava veći broj internet pretraživača.&lt;/p&gt;
&lt;p&gt;U narednom periodu potrudiću se da pi&amp;scaron;em o problemima na koje sam nailazio prilikom kreiranja testova pomoću Selenium WebDriver-a.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/49wOKkJ0YGI" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/11/testiranje-web-a</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/10/connectionstrings-enkripcija</id><title type="text">ConnectionStrings enkripcija</title><published>2011-10-31T23:48:00+01:00</published><updated>2011-10-31T23:48:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/vYmnqkfTG5M/connectionstrings-enkripcija" /><content type="html">&lt;p&gt;S obzirom da se celokupna konfiguarcija ASP.NET aplikacije nalazi u čistom obliku u web.config fajlu, uključujući i connection stringove, ovo svakako predstavlja sigurnosnu pretnju.&lt;/p&gt;
&lt;p&gt;Na svu sreću .Net poseduje mehanizme kojima se ova pretnja lako može otkloniti. Postoje provajderi enkripcije koji mogu da izvr&amp;scaron;e &amp;scaron;ifromanje i de&amp;scaron;ifrovanje određenih web.config sekcija.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;U primeru koji sledi, prikazana je upotreba RSAProtectedConfigurationProvider-a za &amp;scaron;ifrovanje i de&amp;scaron;ifrovanje connectionStrings sekcije.&lt;/p&gt;
&lt;p&gt;Napravićemo novu ASP.NET MVC aplikaciju i izmeniti Index akciju HomeController-a tako da sadrži sledeći kod:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public ActionResult Index()
{
    ViewBag.ConnectionStringsSection = GetConnectionStringsSection();
    return View();
}
&lt;/pre&gt;
&lt;p&gt;Zatim ćemo u HomeController-u napraviti privatnu metodu GetConnectionStringsSection:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;private string GetConnectionStringsSection()
{
    var config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
    var xml = XDocument.Load(config.FilePath);
    var connectionStringsSection = xml.Descendants().SingleOrDefault(e =&amp;gt; e.Name == "connectionStrings");
    return connectionStringsSection != null ? connectionStringsSection.ToString() : string.Empty;
}
&lt;/pre&gt;
&lt;p&gt;A potom ćemo promeniti Index view tako da izgleda ovako:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;div&amp;gt;
    &amp;lt;h2&amp;gt;Connection string encryption example&amp;lt;/h2&amp;gt;
    &amp;lt;p&amp;gt;@Html.ActionLink("Encrypt", "Encrypt")&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;@Html.ActionLink("Decrypt", "Decrypt")&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;
    &amp;lt;h3&amp;gt;Connection Strings section&amp;lt;/h3&amp;gt;
    &amp;lt;p&amp;gt;@ViewBag.ConnectionStringsSection&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;h2&gt;Enkripcija&lt;/h2&gt;
&lt;p&gt;Za enkripciju connectionStrings sekcije napravićemo Encryption akciju u HomeController-u:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public ActionResult Encrypt()
{
    EncryptConnectionStrings();
    return RedirectToAction("Index");
}
&lt;/pre&gt;
&lt;p&gt;Su&amp;scaron;tina je naravno u metodi EncryptConnectionStrings koja izgleda ovako:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public void EncryptConnectionStrings()
{
    var config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
    var section = config.ConnectionStrings;
    if (section.SectionInformation.IsProtected) return;

    section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
    config.Save();
}
&lt;/pre&gt;
&lt;h2&gt;Dekripcija&lt;/h2&gt;
&lt;p&gt;Slično enkripciji, za dekripciju connectionStrings sekcije napravićemo Decryption akciju u HomeController-u:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public ActionResult Decrypt()
{
    DecryptConnectionStrings();
    return RedirectToAction("Index");
}
&lt;/pre&gt;
&lt;p&gt;I naravno, su&amp;scaron;tina je u metodi DecryptConnectionStrings koja izgleda ovako:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;private string GetConnectionStringsSection()
{
    var config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
    var xml = XDocument.Load(config.FilePath);
    var connectionStringsSection = xml.Descendants().SingleOrDefault(e =&amp;gt; e.Name == "connectionStrings");
    return connectionStringsSection != null ? connectionStringsSection.ToString() : string.Empty;
}
&lt;/pre&gt;
&lt;p&gt;Treba imati na umu da su enkripcija i dekripcija skupe operacije, kao i da svaka izmena web.config fajla dovodi do restarta aplikacije.&lt;/p&gt;
&lt;p&gt;Pored ovakvog, programskog načina enkripcije i dekripcije, moguće je ovo postići i pomoću aspnet_regiis.exe konzole. Vi&amp;scaron;e informacija o tome možete naći na &lt;a href="http://msdn.microsoft.com/en-us/library/k6h9cz8h.aspx"&gt;MSDN&lt;/a&gt;-u.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/vYmnqkfTG5M" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/10/connectionstrings-enkripcija</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/10/custom-handleerrorattribute</id><title type="text">Custom HandleErrorAttribute</title><published>2011-10-15T15:05:00+02:00</published><updated>2011-10-15T15:05:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/OROwmW-nGP4/custom-handleerrorattribute" /><content type="html">&lt;p&gt;U okviru ASP.NET MVC framework-a postoji HandleErrorAttribute koji se može koristiti za centralizovanu obradu izuzetaka u MVC aplikaciji. Međutim, već prilikom razvoja prve ASP.NET MVC aplikacije pokazalo se da ovaj atribut nema sve mogućnosti koje su mi potrebne.&lt;/p&gt;
&lt;p&gt;Ono &amp;scaron;to ne dostaje jeste mogućnost da se na neki način kontroli&amp;scaron;e nivo informacija o gre&amp;scaron;ci koji će se prikazati. Drugim rečima, želim da prilikom debug-a mogu da vidim ceo stack trace, dok za release, odnosno za krajnjeg korisika, želim da se prikazuje neka generička poruka o gre&amp;scaron;ci.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;HandleExceptionAttribute&lt;/h2&gt;
&lt;p&gt;Da bih re&amp;scaron;io gore navedeni problem na MVC način, napravio sam novu klasu koja pro&amp;scaron;iruje HandleErrorAttribute.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class HandleExceptionAttribute : HandleErrorAttribute
{
    public HandleExceptionAttribute()
    {
        this.Master = "_MyLayout";
        this.View = "Error";
    }

    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.IsChildAction) return;

        if (IsDebugMode())
        {
            base.OnException(filterContext);
        }
        else
        {
            filterContext.Result = new ViewResult
            {
                ViewName = this.View,
                MasterName = this.Master,
                ViewData = filterContext.Controller.ViewData,
                TempData = filterContext.Controller.TempData
            };
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = 500; //Internal Server Error&amp;nbsp;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            filterContext.ExceptionHandled = true;
        }
    }

    public bool IsDebugMode()
    {
        var compilationSection = WebConfigurationManager.GetSection("system.web/compilation") as CompilationSection;
        return compilationSection != null ? compilationSection.Debug : false;
    }

}
&lt;/pre&gt;
&lt;p&gt;Su&amp;scaron;tina ovog atributa je u IsDebugMode metodi koja proverava da li je aplikacija u debug modu tako &amp;scaron;to proveri pode&amp;scaron;avanja u web.config fajlu. Ukoliko jeste, exception se obrađuje na isti način kao i kod HandleErrorAttribute, u suprotnom prikazujemo neki pogled sa generičkom porukom o gre&amp;scaron;ci.&lt;/p&gt;
&lt;p&gt;Na kraju, da bi ovo funkcinisalo bez potrebe za ručnim setovanjem debug atributa u web.config fajlu, možemo definisati web.config transformaciju.&amp;nbsp;U samom web.config fajlu podesićemo:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;system.web&amp;gt;
    &amp;lt;compilation  debug="true" targetFramework="4.0" defaultLanguage="c#" /&amp;gt;
&amp;lt;/system.web&amp;gt;&lt;/pre&gt;
&lt;p&gt;A zatim u web.Release.config fajlu:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;system.web&amp;gt;
    &amp;lt;compilation xdt:Transform="SetAttributes" debug="false" /&amp;gt;
&amp;lt;/system.web&amp;gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/OROwmW-nGP4" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/10/custom-handleerrorattribute</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/9/msbuild-resources</id><title type="text">MSBuild Resources</title><published>2011-09-30T01:33:00+02:00</published><updated>2011-09-30T01:33:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/n3Pshi58mDw/msbuild-resources" /><content type="html">&lt;p&gt;Pre nekog vremena imao sam priliku da radim kao Build Engineer tako da sam svakodnevno krpio stare i pravio nove buildove. Vrlo često sam morao da potražim neku informaciju ili re&amp;scaron;enje na netu. Nažalost, malo ljudi pi&amp;scaron;e na ovu temu, tako da se sve manje-vi&amp;scaron;e svodi na MSDN dokumentaciju. Svako ko je čitao članke po MSDN-u sigurno se mnogo puta izgubio među mno&amp;scaron;tvom linkova i imao problem da pronađe neki zanimljv članak koji je do samo par minuta čitao. Zbog toga sam ovde izvukao neke korisne linkove.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/0k6kkbsd.aspx"&gt;MSBuild Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd637714.aspx"&gt;MSBuild Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms171458.aspx"&gt;MSBuild Properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb629394.aspx"&gt;Common MSBuild Project Properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa337598.aspx"&gt;Customizable Team Foundation Build Properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms164309.aspx"&gt;MSBuild Reserved Properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms171453.aspx"&gt;MSBuild Items&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb629388.aspx"&gt;Common MSBuild Project Items&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd997067.aspx"&gt;Comparing Properties and Items&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms164313.aspx"&gt;MSBuild Well-known Item Metadata&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms164307.aspx"&gt;MSBuild Conditional Constructs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/7z253716.aspx"&gt;MSBuild Task Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/t9883dzc.aspx"&gt;Task Writing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa337604.aspx"&gt;Customizable Team Foundation Build Targets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms171476.aspx"&gt;MSBuild Transforms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/5dy88c2e.aspx"&gt;MSBuild Project File Schema Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb383819.aspx"&gt;MSBuild Special Characters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/7szfhaft.aspx"&gt;MSBuild Conditions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms164311.aspx"&gt;MSBuild Command Line Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms186195(v=VS.90).aspx"&gt;Resources for Troubleshooting MSBuild Errors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/n3Pshi58mDw" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/9/msbuild-resources</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/9/ajaxonly-kreiranje-custom-actionfilter-a</id><title type="text">AjaxOnly - Kreiranje custom ActionFilter-a</title><published>2011-09-25T22:48:00+02:00</published><updated>2011-09-25T22:48:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/y3aPUcS4fDg/ajaxonly-kreiranje-custom-actionfilter-a" /><content type="html">&lt;p&gt;ActionFilter sadrži logiku koja se može pozvati u nekoliko predefinisanih faza izvr&amp;scaron;avanja action methode. ActionFilter je apstraktna klasa koja nasleđuje FilterAttribute i implementira dva interfejsa: IActionFilter i IResultFilter. Implementacijom ova dva interfejsa zapravo možemo definisati u kojoj fazi izvr&amp;scaron;avanja action metode treba da se izvr&amp;scaron;i logika filtera.&lt;/p&gt;
&lt;p&gt;IActionFilter defini&amp;scaron;e dve metode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OnActionExecuting - ova metoda se izvr&amp;scaron;ava pre action metode&lt;/li&gt;
&lt;li&gt;OnActionExecuted - ova metoda se izvr&amp;scaron;ava neposredno po zavr&amp;scaron;etku action metode&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;IResultFilter defini&amp;scaron;e dve metode i one se izvr&amp;scaron;avaju nakom metoda IActionFilter interfejsa:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OnResultExecuting - ova metoda se izvr&amp;scaron;ava pre renderovanja ActionResult-a&lt;/li&gt;
&lt;li&gt;OnResultExecuted - ova metoda se izvr&amp;scaron;ava nakon renderovanja ActionResult-a&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Kao &amp;scaron;to je rečeno ActionFilter nasledjuje FilterAttribute koja kao baznu ima Attribute klasu. Drugim rečima, ActionFilter se koristi kao i svaka druga .Net atribut klasa, s tom razlikom da je namenjen za dekorisanje action metoda.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[ChildActionOnly]
public ActionResult MyAction()
{
    // some action logic
}
&lt;/pre&gt;
&lt;p&gt;ASP.NET MVC sadrži nekoliko predefinisanih atributa koji se mogu iskoristiti za dekorisanje action metoda:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Authorize&lt;/li&gt;
&lt;li&gt;ChildActionOnly&lt;/li&gt;
&lt;li&gt;OutputCache&lt;/li&gt;
&lt;li&gt;ValidateAntiForderyToken&lt;/li&gt;
&lt;li&gt;itd.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Filteri se mogu primeniti nad kontrolerima i u tom slučaju će važiti za sve action metode kontrolera.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[Authorize]
public class MyController : Controller
{
    // ...
}
&lt;/pre&gt;
&lt;p&gt;Pored toga, sa ASP.NET MVC 3 verzijom moguće je definisati i globalne filtere koji će važiti za sve kontrolere, odnosno njihove action metode. Za tu svrhu potrebno je u Application_Start metodi dodati željene filtere.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;protected void Application_Start()
{
    RegisterGlobalFilters(GlobalFilters.Filters);
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
}

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
}
&lt;/pre&gt;
&lt;p&gt;Osnovna ideja filtera je da se određena logika centralizuje kako bi se mogla primeniti na vi&amp;scaron;e action metoda. Svrha ActionFilter klase je da posluži kao bazna klasa za custom filtere.&lt;/p&gt;
&lt;h2&gt;AjaxOnly&lt;/h2&gt;
&lt;p&gt;Kao primer kreiranja custom filtera, kreiraćemo AjaxOnly filter koji ima za cilj da filtrira zahteve tako da se action metoda dekorisana sa ovim atributom može okinuti samo u slučaju ajax zahteva.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class AjaxOnlyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.HttpContext.Response.RedirectToRoute("PageNotFound");
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;Kada neku action metogu dekori&amp;scaron;emo sa ovim atributom, pre njenog izvr&amp;scaron;avanja okinuće se ovaj filter, odnosno OnActionExecuting metoda. Filter proverava da li je u pitanju Ajax zahtev. U slučaju da nije vr&amp;scaron;i redirekciju na rutu PageNotFound koja, pretpostavljate, se mapira na action metodu koja renderuje PageNotFound pogled.&lt;/p&gt;
&lt;p&gt;U slučaju da jeste Ajax zahtev, filter ne radi ni&amp;scaron;ta, odnosno tok izvr&amp;scaron;avanja se nastavlja normalnim putem i action metoda se izvr&amp;scaron;ava a zatim renderuje odgovarajući pogled.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[AjaxOnly]
public ActionResult Vote(int value)
{
    if (ModelState.IsValid)
    {
        //save vote in db
        //return ok
    }
    else
    {
        //return fail
    }
}
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/y3aPUcS4fDg" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/9/ajaxonly-kreiranje-custom-actionfilter-a</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/8/windows-phone-7-resources</id><title type="text">Windows Phone 7 Resources</title><published>2011-08-25T00:03:00+02:00</published><updated>2011-08-25T00:03:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/p2MNiI1X5oY/windows-phone-7-resources" /><content type="html">&lt;p&gt;U marketing Windows Phone 7 je uloženo zaista mnogo, i moram priznati da nisam ni ja uspeo da odolim a da se ne oprobam u razvoj mobilnih aplikacija. Evo nekoliko korisnih adresa koje vam mogu pomoći da brže i lak&amp;scaron;e počnete sa Windows Phone 7 razvojem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ff402531.aspx"&gt;Application Platform Overview for Windows Phone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ff402535.aspx"&gt;Windows Phone Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://create.msdn.com/en-us/home/getting_started"&gt;Getting started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://create.msdn.com/en-us/education/gamedevelopment"&gt;Game development&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Tutorijali:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://create.msdn.com/en-us/education/quickstarts"&gt;Windows Phone development quickstarts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ff431744.aspx"&gt;Code samples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Video tutorijali:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://create.msdn.com/en-US/education/catalog/article/wp7_jump_start"&gt;Windows Phone 7 Jump Start&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/b/jaimer/archive/2010/08/13/windows-phone-design-day-recordings.aspx"&gt;Windows Phone Design Day Recordings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://channel9.msdn.com/Tags/windows+phone"&gt;Channel 9&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Besplatne knjige:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/b/microsoft_press/archive/2010/10/28/free-ebook-programming-windows-phone-7-by-charles-petzold.aspx"&gt;Windows Phone 7 Programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.robmiles.com/journal/2010/12/16/free-ldquowindows-phone-blue-bookrdquo-course.html"&gt;Windows Phone 7 Programming - Free book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg490765.aspx"&gt;Windows Phone 7 Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://microsoftfeed.com/2011/free-ebook-silverlight-for-windows-phone/"&gt;Silverlight for Windows Phone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://windowsteamblog.com/windows_phone/b/wpdev/archive/2010/03/18/windows-phone-7-series-ui-design-amp-interaction-guide.aspx"&gt;Windows Phone 7 Series UI Design &amp;amp; Interaction Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Linkovi:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://windowsphonegeek.com/Resources"&gt;Windows Phone Geek&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mark-kirby.co.uk/2010/the-best-resources-for-windows-phone-7-development/"&gt;Mark Kirby blogpost&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/p2MNiI1X5oY" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/8/windows-phone-7-resources</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/7/testiranje-ruta</id><title type="text">Testiranje ruta</title><published>2011-07-17T23:36:00+02:00</published><updated>2011-07-17T23:36:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/fB7cD0d1phA/testiranje-ruta" /><content type="html">&lt;p&gt;ASP.NET MVC framework je osmi&amp;scaron;ljen tako da može lako da se testira. Medutim, u nekim slucajevima testiranje MVC aplikacije može biti složeniji posao.&lt;/p&gt;
&lt;p&gt;Mehanizam za rutiranje se direktno oslanja na ASP.NET i napravljen je tako da radi i sa ASP.NET WebForms i sa ASP.NET MVC framework-om. Zbog toga je za testiranje ruta potrebno kreirati dosta Mock objekata. Iako ovo nije te&amp;scaron;ko uraditi, može da bude iscrpljujuće.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Na svu sreću postoji bibiloteka koja pomaže u instanciranju kontrolera i pravilnom inicijalizovanju njegovih članica:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HttpContext&lt;/li&gt;
&lt;li&gt;HttpRequest&lt;/li&gt;
&lt;li&gt;HttpResponse&lt;/li&gt;
&lt;li&gt;HttpSession&lt;/li&gt;
&lt;li&gt;Form&lt;/li&gt;
&lt;li&gt;TempData&lt;/li&gt;
&lt;li&gt;QueryString&lt;/li&gt;
&lt;li&gt;ApplicationPath&lt;/li&gt;
&lt;li&gt;PathInfo&lt;/li&gt;
&lt;li&gt;itd.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;U okviru Codeplex projekta MvcContrib postoji biblioteka &lt;a href="http://mvccontrib.codeplex.com/wikipage?title=TestHelper&amp;amp;referringTitle=Documentation"&gt;TestHelper&lt;/a&gt; koja sadrži sve &amp;scaron;to nam je potrebno za testiranje ruta. MvcContrib TestHelper može da se doda u test projekat kao NuGet paket:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;PM&amp;gt; Install-Package MvcContrib.Mvc3.TestHelper-ci&lt;/pre&gt;
&lt;p&gt;Nakon &amp;scaron;to smo dodali referencu na TestHelper biblioteku, potrebno je da učitamo rute. To ćemo učiniti u okviru ClassInitialize metode:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[ClassInitialize]
public static void MyClassInitialize(TestContext testContext)
{
    RouteTesting.Demo.MvcApplication.RegisterRoutes(RouteTable.Routes);
}
&lt;/pre&gt;
&lt;p&gt;Sada možemo da pi&amp;scaron;emo testove za rute:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[TestMethod]
public void GET_Account_LogOn()
{
    "~/Account/LogOn".ShouldMapTo&amp;lt;AccountController&amp;gt;(ac =&amp;gt; ac.LogOn());
}

[TestMethod]
public void POST_Account_LogOn()
{
    "~/Account/LogOn".WithMethod(HttpVerbs.Post).ShouldMapTo&amp;lt;AccountController&amp;gt;(ac =&amp;gt; ac.LogOn(null, null));
}
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/fB7cD0d1phA" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/7/testiranje-ruta</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/7/feedresult</id><title type="text">FeedResult - Kreiranje custom ActionResult-a</title><published>2011-07-13T23:49:00+02:00</published><updated>2011-07-13T23:49:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/VxDyhrX8KaQ/feedresult" /><content type="html">&lt;p&gt;U ovom postu biće prikazano kako može da se napravi custom ActionResult koji vraća feed kao odgovor na zahteva browser-a.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h2&gt;ActionResult&lt;/h2&gt;
&lt;p&gt;Svaka akcija kontrolera vraća objekat koji proizilazi iz apstraktne &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.actionresult.aspx"&gt;ActionResult&lt;/a&gt; klase. ASP.NET MVC sadrži nekoliko klasa koje nasleđuju ActionResult:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ContentResult&lt;/li&gt;
&lt;li&gt;EmptyResult&lt;/li&gt;
&lt;li&gt;FileResult (apstraktna)&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;FileContentResult&lt;/li&gt;
&lt;li&gt;FilePathResult&lt;/li&gt;
&lt;li&gt;FileStreamResult&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;HttpUnauthorizedResult&lt;/li&gt;
&lt;li&gt;JavaScriptResult&lt;/li&gt;
&lt;li&gt;JsonResult&lt;/li&gt;
&lt;li&gt;RedirectResult&lt;/li&gt;
&lt;li&gt;RedirectToRouteResult&lt;/li&gt;
&lt;li&gt;ViewResultBase (apstraktna)&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;PartialViewResult&lt;/li&gt;
&lt;li&gt;ViewResult&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p&gt;ActionResult klasa sadrži samo jednu metodu, tako da ako pravimo custom ActionResult potrebno je da preklopimo samo ExecuteResult metodu. Iako, u na&amp;scaron;em primeru možemo direktno da nasledimo ActionResult klasu, mi ćemo naslediti &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.fileresult.aspx"&gt;FileResult&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;S obzirom da je MVC open source projekat, evo i &lt;a href="http://aspnet.codeplex.com/SourceControl/BrowseLatest"&gt;source&lt;/a&gt;-a ove dve klase:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;    public abstract class ActionResult {
        public abstract void ExecuteResult(ControllerContext context);
    }

     public abstract class FileResult : ActionResult {

        protected FileResult(string contentType) {
            if (String.IsNullOrEmpty(contentType)) {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "contentType");
            }

            ContentType = contentType;
        }

        private string _fileDownloadName;

        public string ContentType {
            get;
            private set;
        }

        public string FileDownloadName {
            get {
                return _fileDownloadName ?? String.Empty;
            }
            set {
                _fileDownloadName = value;
            }
        }

        public override void ExecuteResult(ControllerContext context) {
            if (context == null) {
                throw new ArgumentNullException("context");
            }

            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = ContentType;

            if (!String.IsNullOrEmpty(FileDownloadName)) {
                // From RFC 2183, Sec. 2.3:
                // The sender may want to suggest a filename to be used if the entity is
                // detached and stored in a separate file. If the receiving MUA writes
                // the entity to a file, the suggested filename should be used as a
                // basis for the actual filename, where possible.
                ContentDisposition disposition = new ContentDisposition() { FileName = FileDownloadName };
                string headerValue = disposition.ToString();
                context.HttpContext.Response.AddHeader("Content-Disposition", headerValue);
            }

            WriteFile(response);
        }

        protected abstract void WriteFile(HttpResponseBase response);

    }
&lt;/pre&gt;
&lt;p&gt;Kako bi browser shvatio da se radi o feed-u, potrebno je da u response-u dodamo header Content-Disposition sa vredno&amp;scaron;ću application/rss+xml. Ovo je ujedno i razlog za&amp;scaron;to ćemo naslediti FileResult umesto ActionResult.&lt;/p&gt;
&lt;h2&gt;Atom i RSS&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Atom_(standard)"&gt;Atom&lt;/a&gt;&amp;nbsp;i &lt;a href="http://en.wikipedia.org/wiki/RSS"&gt;Rss&lt;/a&gt;&amp;nbsp;predstavljaju dijalekte XML-a, ali na svu sreću nije potrebno da se bavimo parsiranjem XML-a. U .NET-u postoji skup klasa koje su namenjen za rad sa strukturama podataka kakve su Atom i Rss feed-ovi. U prostoru imena &lt;a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.syndication.aspx"&gt;System.ServiceModel.Syndication&lt;/a&gt; nalazi se nekoliko klasa:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SyndicationFeed&lt;/li&gt;
&lt;li&gt;SyndicationItem&lt;/li&gt;
&lt;li&gt;SyndicationContent&lt;/li&gt;
&lt;li&gt;itd.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Implementacija&lt;/h2&gt;
&lt;p&gt;Uzećemo za primer blog aplikaciju, odnosno Post klasu kao model za koji ćemo generisati feed:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class Post
{
    public int PostId { get; set }
    public string Title { get; set; }
    public string Body { get; set; }
    public string Permalink { get; set; }
    public DateTime Posted { get; set; }
}
&lt;/pre&gt;
&lt;p&gt;FeedController je krajnje jednostavan i mislim da nema potrebe detaljnije obja&amp;scaron;njavati &amp;scaron;ta radi:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class FeedController : Controller
{
	private BlogContext db = new BlogContext();
	
	public ActionResult Atom()
	{
		var posts = db.Posts.All();
		return FeedResult(posts, FeedFormat.Atom10);
	}
	
	public ActionResult Rss()
	{
		var posts = db.Posts.All();
		return FeedResult(posts, FeedFormat.Rss20);
	}	
}
&lt;/pre&gt;
&lt;p&gt;FeedResult izgledaće ovako:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;    public class FeedResult : FileResult
    {
        private IEnumerable items;
        private FeedFormat feedFormat;
        private Uri currentUrl;
        public SyndicationFeed Feed { get; set; }

        public FeedResult(IEnumerable items, FeedFormat format)
            : base("application/rss+xml")
        {
            this.items = items;
            this.feedFormat = format;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            this.currentUrl = context.RequestContext.HttpContext.Request.Url;
            base.ExecuteResult(context);
        }

        protected override void WriteFile(HttpResponseBase response)
        {
            Feed = new SyndicationFeed("Feed title", "Feed description", this.currentUrl, GetSyndicationItems());            
            Feed.Authors.Add(new SyndicationPerson("my@email.com", "My Name", "MyBlogUrl"));            
            Save(XmlWriter.Create(response.Output));
        }

        private void Save(XmlWriter writer)
        {
            switch (this.feedFormat)
            {
                case FeedFormat.Atom10:
                    Feed.SaveAsAtom10(writer);
                    break;
                case FeedFormat.Rss20:
                    Feed.SaveAsRss20(writer);
                    break;
                default:
                    Feed.SaveAsRss20(writer);
                    break;
            }
            writer.Close();
        }

        private List GetSyndicationItems()
        {
            var items = new List();
            foreach (var post in this.items)
            {
                var item = new SyndicationItem
                {
                    Title = SyndicationContent.CreatePlaintextContent(post.Title),
                    Content = SyndicationContent.CreateHtmlContent(post.Body),
                    Id = post.PostId.ToString(),
                    PublishDate = post.Posted,
                    LastUpdatedTime = post.Posted
                };
                item.AddPermalink(new Uri(post.Permalink));
                items.Add(item);
            }
            return items;
        }
    }

    public enum FeedFormat
    {
        Atom10,
        Rss20
    }
&lt;/pre&gt;
&lt;p&gt;Mislim da kod FeedResult-a dovoljno sam sebe obja&amp;scaron;njava, treba samo obratiti pažnju na dve metode koje su preklopljne: WriteFile i ExecuteResult. ExecuteResult je metoda nasleđena od ActionResult-a i nju okida &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.controlleractioninvoker.aspx"&gt;ControllerActionInvoker&lt;/a&gt;. WriteFile je nasleđena on FileResult klase i ona je odgovorna za pisanje sadržaja fajla u response. U slučaju nekog fajla to bi bio niz bajtova, a u na&amp;scaron;em slučaju to je sadržaj XML fajla (Atom ili RSS feed).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/VxDyhrX8KaQ" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/7/feedresult</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/6/content-delivery-network</id><title type="text">CDN - Content Delivery Network</title><published>2011-06-23T23:19:00+02:00</published><updated>2011-06-23T23:19:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/mOen_It9eOE/content-delivery-network" /><content type="html">&lt;p&gt;CDN predstavlja mrežu servera koji imaju isti sadržaj ali su geografski razme&amp;scaron;teni na vi&amp;scaron;e lokacija. Kada krajnji korisnik po&amp;scaron;alje zahtev za nekom stranicom, CDN dinamički izračunava koji CDN server mu je geografski najbliži i &amp;scaron;elje odgovor sa tog servera. Sofisticiraniji CDN sistemi mogu da vr&amp;scaron;e i balansiranje opterećenja ukoliko u datom trenutku dođe do velikog saobraćaja na nekoj geografskoj lokaciji.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Bez CDN-a web sajt se servira sa jedne geografske lokacije na kojoj se nalazi jedan server. Veliki saobraćaj ili velika distanca između servera i krajnjeg korisnika može negativno da utiče na brzinu učitavanja stranica web sajta.&lt;/p&gt;
&lt;p&gt;Posetioci sajta najče&amp;scaron;će nisu voljni da čekaju vi&amp;scaron;e od par sekundi za učitavanje stranice. Zbog toga je jako važno smanjiti vreme odziva servera na klijentski zahtev.&lt;/p&gt;
&lt;p&gt;Na neki način, CDN igra sličnu ulogu za servere kao proxy za klijente. Proxy server je često fizički bliže krajnjem korisniku ili, &amp;scaron;to je jo&amp;scaron; bitnije, ima bržu konekciju sa krajnjim korisnikom, tako da u slučaju da ima u svom ke&amp;scaron;u traženu stranicu (ili bilo koji drugi sadržaj) može brže da je isporuči krajnjem korisniku nego izvorni server. CDN povećava ukupni protok zbog toga &amp;scaron;to se sastoji od većeg broja servera sa istim sadržajem, a s druge strane, smanjuje vreme odgovora usled manje geografske distance između servera i krajnjeg korisnika.&lt;/p&gt;
&lt;h2&gt;Prednosti upotrebe CDN&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Povećava propusnu moć&lt;/li&gt;
&lt;li&gt;Povećava redudantnost&lt;/li&gt;
&lt;li&gt;Smanjuje latenciju&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kada se serviraju fajlovi malih veličina, CDN doprinosi bržem učitavanju stranica usled manje latencije, a u slučaju velikih fajlova CDN obezbeđuje veće brzine download-a usled povećane propusne moći.&lt;/p&gt;
&lt;p&gt;Redudantnost podataka obezbeđuje veću dostupnost, odnosno postepenu degradaciju u slučaju otkaza servera ili zagu&amp;scaron;enja saobraćaja na internetu.&lt;/p&gt;
&lt;h2&gt;Upotreba CDN-a&lt;/h2&gt;
&lt;p&gt;Zbog svoje velike popularnosti neke JavaScript biblioteke kao &amp;scaron;to su jQuery i jQuery UI su dostupni preko Google ili Microsoft CDN-a.&lt;/p&gt;
&lt;p&gt;S obzirom da browser-i ke&amp;scaron;iraju sav statički sadržaj kao &amp;scaron;to su CSS i JavaScript fajlovi, ukoliko se korite neki od ovih CDN-a, vrlo je verovatno da će se neke od popularnih JavaScript biblioteka već naći u ke&amp;scaron;u krajnjeg korisnika.&lt;/p&gt;
&lt;p&gt;Da bi koristili Google CDN-u za jQuery bibilioteku potrebno je samo referencirati skriptu sa odgovarajuće adrese:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js"&amp;gt;&amp;lt;/script&amp;gt;

&lt;/pre&gt;
&lt;p&gt;ili za minimizaranu verziju:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"&amp;gt;&amp;lt;/script&amp;gt;

&lt;/pre&gt;
&lt;p&gt;Takođe, možemo i upotrebiti Google libraries API i pozvati load funkciju za učitavanje željene biblioteke:&lt;/p&gt;
&lt;pre class="brush: js"&gt;google.load("jquery", "1.6.2");

&lt;/pre&gt;
&lt;p&gt;Za vi&amp;scaron;e informacija o Google CDN-u i ostalim JavaScript bibliotekama možete pogledati zvaničnu &lt;a href="http://code.google.com/apis/libraries/devguide.html"&gt;dokumentaciju&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pored Google CDN-a i Microsoft ima besplatan CDN za popularne JavaScript biblioteke:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.js"&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.14/jquery-ui.js"&amp;gt;&amp;lt;/script&amp;gt;

&lt;/pre&gt;
&lt;p&gt;ili za minimizaranu verziju:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.min.js"&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.14/jquery-ui.min.js"&amp;gt;&amp;lt;/script&amp;gt;

&lt;/pre&gt;
&lt;p&gt;Za vi&amp;scaron;e informacija posetite ASP.NET CDN &lt;a href="http://www.asp.net/ajaxlibrary/cdn.ashx"&gt;dokumentaciju&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/mOen_It9eOE" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/6/content-delivery-network</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/6/dependency-injection-castle-windsor</id><title type="text">Dependency Injection - Castle Windsor</title><published>2011-06-12T15:33:00+02:00</published><updated>2011-06-12T15:33:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/Ejv-7UniozY/dependency-injection-castle-windsor" /><content type="html">&lt;p&gt;Poslednji IoC kontejner u ovom serijalu je &lt;a href="http://www.castleproject.org/container/"&gt;Castle Windsor&lt;/a&gt;. Ovaj IoC kontejner je deo &lt;a href="http://www.castleproject.org/castle/projects.html"&gt;Castle&lt;/a&gt; projekta iza koga stoji grupa iskusnih .Net developer-a.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Jednostavna implementacija IDependencyResolver interfejsa pomoću Castle Windsor IoC kontejnera bi izgledala ovako:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;    public class CastleWindsorDependencyResolver : IDependencyResolver
    {
        private IKernel kernel;

        public CastleWindsorDependencyResolver(IKernel kernel)
        {
            this.kernel = kernel;
        }

        public object GetService(Type serviceType)
        {
            try
            {
                return this.kernel.Resolve(serviceType);
            }
            catch
            {
                return null;
            }
        }

        public IEnumerable&amp;lt;object&amp;gt; GetServices(Type serviceType)
        {
            try
            {
                return this.kernel.ResolveAll(serviceType).Cast&amp;lt;IEnumerable&amp;lt;object&amp;gt;&amp;gt;();
            }
            catch
            {
                return new List&amp;lt;object&amp;gt;();
            }
        }
    }
&lt;/pre&gt;
&lt;p&gt;Na kraju, konfigurisanje Castle Windsor IoC kontejnera treba izvr&amp;scaron;iti unutar Global.asax.cs fajla:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;    protected void Application_Start()
    {
		RegisterCastleWindsorDependencyResolver();
		RegisterGlobalFilters(GlobalFilters.Filters);
		RegisterRoutes(RouteTable.Routes);
	}

    private void RegisterCastleWindsorDependencyResolver()
    {
        var container = new WindsorContainer()
            .Register(Component.For&amp;lt;HomeController&amp;gt;())
            .Register(Component.For&amp;lt;IRepository&amp;gt;().ImplementedBy&amp;lt;ConcreteRepository&amp;gt;());
            
        DependencyResolver.SetResolver(
            new CastleWindsorDependencyResolver(container.Kernel));
    }
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/Ejv-7UniozY" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/6/dependency-injection-castle-windsor</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/6/dependency-injection-structuremap</id><title type="text">Dependency Injection - StructureMap</title><published>2011-06-01T14:46:00+02:00</published><updated>2011-06-01T14:46:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/7nDlemmdfUU/dependency-injection-structuremap" /><content type="html">&lt;p&gt;&lt;a href="http://structuremap.net/structuremap/"&gt;StructureMap&lt;/a&gt; je jedan od najstarijih a samim tim i najzrelijih IoC kontejnera za .Net. Prva stabilna verzija iza&amp;scaron;la je jo&amp;scaron; 2004., a trenutno aktuelna verzija 2.6.1 je iz februara 2010.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Jednostavna implementacija IDependencyResolver interfejsa pomoću StructureMap IoC kontejnera bi izgledala ovako:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;    public class StructureMapDependencyResolver : IDependencyResolver
    {
        private readonly IContainer container;

        public StructureMapDependencyResolver(IContainer container)
        {
            this.container = container;
        }

        public object GetService(Type serviceType)
        {
            try
            {
                return this.container.GetInstance(serviceType);
            }
            catch
            {
                return null;
            }
        }

        public IEnumerable&amp;lt;object&amp;gt; GetServices(Type serviceType)
        {
            try
            {
                return this.container.GetAllInstances(serviceType).Cast&amp;lt;object&amp;gt;();
            }
            catch
            {
                return new List&amp;lt;object&amp;gt;();
            }
        }
    }
&lt;/pre&gt;
&lt;p&gt;Konfigurisanje SturctureMap kontejnera treba izvr&amp;scaron;iti unutar Global.asax.cs fajla:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;protected void Application_Start()
{
    RegisterStructureMapDependencyResolver();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

private void RegisterStructureMapDependencyResolver()
{
    var container = new Container(
        x =&amp;gt; x.For&amp;lt;IRepository&amp;gt;().Use&amp;lt;ConcreteRepository&amp;gt;());
            
    DependencyResolver.SetResolver(
        new StructureMapDependencyResolver(container));
}
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/7nDlemmdfUU" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/6/dependency-injection-structuremap</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/5/dependency-injection-autofac</id><title type="text">Dependency Injection - Autofac</title><published>2011-05-21T13:31:00+02:00</published><updated>2011-05-21T13:31:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/SCx1fFIa_k0/dependency-injection-autofac" /><content type="html">&lt;p&gt;&lt;a href="http://code.google.com/p/autofac/"&gt;Autofac&lt;/a&gt; je jo&amp;scaron; jedan IoC kontejner za .Net, takođe vrlo popularan. Odlikuje ga manja veličina biblioteka u odnosu na ostale IoC kontejnere, ali ne i nedostatak funkcionalnosti.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Jednostavna implementacija IDependencyResolver interfejsa pomoću Autofac framework-a bi izgledala ovako:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class AutofacDependencyResolver : IDependencyResolver
{
    private IContainer container;

    public AutofacDependencyResolver(Autofac.IContainer container)
    {
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return this.container.Resolve(serviceType);
        }
        catch
        {
            return null;
        }
    }

    public IEnumerable&amp;lt;object&amp;gt; GetServices(Type serviceType)
    {
        try
        {
            Type type = typeof(IEnumerable).MakeGenericType(
            new Type[]
            {
                serviceType
            });
            object obj = this.container.Resolve(type);
            return (IEnumerable&amp;lt;object&amp;gt;)obj;
        }
        catch
        {
            return new List&amp;lt;object&amp;gt;();
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;Setup Autofac IoC kontejnera treba staviti u Global.asax.cs fajl:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;protected void Application_Start()
{
    RegisterAutofacDependencyResolver();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

private void RegisterAutofacDependencyResolver()
{
    var builder = new ContainerBuilder();
    builder.RegisterType&amp;lt;HomeController&amp;gt;();
    builder.RegisterType&amp;lt;ConcreteRepository&amp;gt;().As&amp;lt;IRepository&amp;gt;();

    DependencyResolver.SetResolver(
    new AutofacDependencyResolver(builder.Build()));
}
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/SCx1fFIa_k0" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/5/dependency-injection-autofac</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/5/dependency-injection-ninject</id><title type="text">Dependency Injection - Ninject</title><published>2011-05-18T22:12:00+02:00</published><updated>2011-05-18T22:12:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/0LeIlGpYR34/dependency-injection-ninject" /><content type="html">&lt;p&gt;&lt;a href="http://ninject.org/"&gt;Ninject&lt;/a&gt;&amp;nbsp;je open source DI framework, besplatan za ličnu i komercijalnu upotrebu. U .Net zajednici možda i najpopularniji. Odlikuje ga jednostavna i simpatična sintaksa, kao i vrlo dobra &lt;a href="https://github.com/ninject/ninject/wiki"&gt;dokumentacija&lt;/a&gt; koja do detalja obja&amp;scaron;njava njegovu upotrebu.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Jednostavna implementacija &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.idependencyresolver.aspx"&gt;IDependencyResolver&lt;/a&gt; interfejsa pomoću Ninject DI framework-a bi izgledala ovako:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class NinjectDependencyResolver : IDependencyResolver
{
    private readonly IKernel kernel;

    public NinjectDependencyResolver(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return this.kernel.Get(serviceType);
        }
        catch
        {
            return null;
        }
    }

    public IEnumerable&amp;lt;object&amp;gt; GetServices(Type serviceType)
    {
        try
        {
            return this.kernel.GetAll(serviceType);
        }
        catch
        {
            return new List&amp;lt;object&amp;gt;();
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;Na kraju, potrebno je podesiti IoC kontejner unutar Global.asax.cs fajla:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;protected void Application_Start()
{
    RegisterNinjectDependencyResolver();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

private void RegisterNinjectDependencyResolver()
{
    var kernel = new StandardKernel();
    kernel.Bind&amp;lt;IRepository&amp;gt;().To&amp;lt;ConcreteRepository&amp;gt;();
    DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/0LeIlGpYR34" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/5/dependency-injection-ninject</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/5/dependency-injection</id><title type="text">Dependency Injection</title><published>2011-05-12T22:54:00+02:00</published><updated>2011-05-12T22:54:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/BnsnboezhE8/dependency-injection" /><content type="html">&lt;p&gt;U skoro svakom tutorijalu o ASP.NET MVC framework-u se pominje &lt;a href="http://martinfowler.com/articles/injection.html"&gt;Dependency Injection&lt;/a&gt;. Međutim, IoC framework-a ima dosta, a svako ima neki omiljeni.&lt;/p&gt;
&lt;p&gt;U svim tim tutorijalima kada pi&amp;scaron;u o DI, autori uvek prezentuju jedan od IoC framwork-a, tako da je te&amp;scaron;ko naći tutorijal ili blog na kome su dati primeri za vi&amp;scaron;e IoC framework-a. Zbog toga je te&amp;scaron;ko odlučiti se koji koristiti, naročito ako ste tek počeli da učite.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Zbog toga sam odlučio da napi&amp;scaron;em seriju postova u kojima ću prikazati neke od najpopularnijih IoC framework-a.&lt;/p&gt;
&lt;p&gt;Primeri u ovoj seriji postova obuhvataju sledeće IoC framework-e:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="../../2011/5/dependency-injection-unity"&gt;Unity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="../../../2011/5/dependency-injection-ninject"&gt;Ninject&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="../../../2011/5/dependency-injection-autofac"&gt;Autofac&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="../../../2011/6/dependency-injection-structuremap"&gt;StructureMap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="../../../2011/6/dependency-injection-castle-windsor"&gt;Castle Windsor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Jedno od glavnih pobolj&amp;scaron;anja koje nam MVC 3 donsi jeste bolja integracija sa IoC/DI kontejnerima. U ranijim verzijama MVC framework-a bilo je potrebno napraviti custom ControllerFactory. U MVC 3 potrebno je samo implementirati jedan jednostavan interfejs:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public interface IDepndencyResolver
{
    object GetService(Type serviceType);
    IEnumerable&amp;lt;object&amp;gt; GetServices(Type serviceType);
}&lt;/pre&gt;
&lt;p&gt;Treba napomenuti da ukoliko pri pozivu GetService metode IoC kontejner nije u stanju da vrati servis, treba da vrati null. Slično tome ukoliko pri pozivu GetServices nije u stanju da vrati servise treba da vrati praznu kolekciju. Ovo je vrlo bitno, jer ukoliko dođe do gre&amp;scaron;ke ona će biti vraćena korisniku kao run-time gre&amp;scaron;ka.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/BnsnboezhE8" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/5/dependency-injection</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/5/dependency-injection-unity</id><title type="text">Dependency Injection - Unity</title><published>2011-05-04T21:39:00+02:00</published><updated>2011-05-04T21:39:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/9V68Ri7-Daw/dependency-injection-unity" /><content type="html">&lt;p&gt;Jedno od glavnih pobolj&amp;scaron;anja koje nam MVC 3 donsi jeste bolja integracija sa &lt;a href="http://en.wikipedia.org/wiki/Inversion_of_control"&gt;IoC&lt;/a&gt;/&lt;a href="http://en.wikipedia.org/wiki/Dependency_injection"&gt;DI&lt;/a&gt; kontejnerima. U ranijim verzijama MVC framework-a bilo je potrebno napraviti custom ControllerFactory. Međutim, postoji veliki broj IoC framework-a tako da je prirodnije da se komunikacija sa MVC framework-om odvija preko nekog interfejsa.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Za tu svrhu postoji jedan vrlo jednostavan interfejs - &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.idependencyresolver.aspx"&gt;IDependencyResolver&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public interface IDepndencyResolver
{
    object GetService(Type serviceType);
    IEnumerable&amp;lt;object&amp;gt; GetServices(Type serviceType);
}
&lt;/pre&gt;
&lt;p&gt;I upravo implementacije ovog interfejsa treba da delegiraju zahteve za tipovima konkretnom IoC kontejneru.&lt;/p&gt;
&lt;p&gt;UnityDependencyResolver:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class UnityDependencyResolver : IDependencyResolver
{
    private readonly IUnityContainer container;

    public UnityDependencyResolver(IUnityContainer container)
    {
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return this.container.Resolve(serviceType);
        }
        catch
        {
            return null;
    }

    public IEnumerable&amp;lt;object&amp;gt; GetServices(Type serviceType)
    {
        try
        {
            return this.container.ResolveAll(serviceType);
        }
        catch
        {
            return new List&amp;lt;object&amp;gt;();
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;Ovde treba obratiti pažnju na to da ukoliko GetService nije u mogućnosti da vrati servis, treba da vrati null. I slično, ukoliko GetServices ne može da vrati servise treba da vrati praznu kolekciju. Ovo je važno jer ukoliko dođe do izuzetka on će biti vraćen korisniku kao run-time gre&amp;scaron;ka.&lt;/p&gt;
&lt;p&gt;Nakon sto smo implementirali IDependencyResolver interfejs, potrebno je napuniti IoC kontejner:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;protected void Application_Start()
{
    RegisterDependencyResolver();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

private void RegisterDependencyResolver()
{
    var container = new UnityContainer()
                        .RegisterType&amp;lt;IRepository, ConcreteRepository&amp;gt;()
                        .RegisterType&amp;lt;IService, ConcreteService&amp;gt;();
    DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/9V68Ri7-Daw" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/5/dependency-injection-unity</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/4/anatomija-test-klase</id><title type="text">Anatomija test klase</title><published>2011-04-25T22:20:00+02:00</published><updated>2011-04-25T22:20:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/W7QI_yGpodc/anatomija-test-klase" /><content type="html">&lt;p&gt;Sve test klase moraju biti dekorisane sa atributom [TestClass]. Na ovaj nacin Visual Studio prepoznaje da ta klasa sadrži testove. Pored ovog atributa, test klasa mora da bude javna i mora da ima bezparametarski javni konstruktor.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestProject1
{
	[TestClass]
	public class UnitTest1
	{
		[TestMethod]
		public void TestMethod1()
		{
		}
	}
}
&lt;/pre&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Unutar test klase, svaka test metoda mora da bude javna, bezparametarska i da ne vraca vrednost. Da bi se smatrala test metodom, mora da bude dekorisana sa [TestMethod] atributom. Ukoliko neki od atributa nedostaje, nece biti prijavljene nikakve gre&amp;scaron;ke, vec &amp;nbsp;jednostavno nece biti testova za izvr&amp;scaron;avanje. Medutim, ukoliko postoje atributi, ali nisu ispunjeni neki drugi zahtevi bice prijavljene gre&amp;scaron;ke.&lt;/p&gt;
&lt;h2&gt;Pripremne i zavr&amp;scaron;ne akcije&lt;/h2&gt;
&lt;p&gt;U odredenim situacijama potrebno je izv&amp;scaron;iti neke pripremne i zavr&amp;scaron;ne akcije kako bi testovi mogli da se izvr&amp;scaron;e. Na primer, ukoliko deo koda koji testiramo zavisi od nekog izvora podataka, potrebno je pripremiti podatke bilo &amp;nbsp; putem lažnog (fake) izvora podataka ili iz pravog izvora podataka. Ovaj pripremni skup akcija možemo izdvojiti u zasebnu metodu ukoliko ih je potrebno izvr&amp;scaron;iti pre svakog testa.&lt;/p&gt;
&lt;p&gt;Za tu svrhu postoji nekoliko atributa kojima se mogu dekorisati odgovarajuce metode. Tu spadaju:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AssemblyInitialize&lt;/li&gt;
&lt;li&gt;AssemblyCleanup&lt;/li&gt;
&lt;li&gt;ClassInitialize&lt;/li&gt;
&lt;li&gt;ClassCleanup&lt;/li&gt;
&lt;li&gt;TestInitialize&lt;/li&gt;
&lt;li&gt;TestCleanup&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Metode sa [AssemblyInitialize]/[AssemblyCleanup] atributom se pozivaju jednom pre nego &amp;scaron;to se pozove ijedan test u celoj test biblioteci, dok se cleanup poziva nakon svih testova. Može da postoji samo po jedna ovakva metoda u celoj test biblioteci. &amp;nbsp;Primer bi izgledao ovako:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[AssemblyInitialize]
public static void AssemblyInit(TestContext context)
{
}
&lt;/pre&gt;
&lt;p&gt;Metode dekorisane sa atributima [ClassInitlialize] &amp;nbsp;se pokrecu pre prvog testa unutar neke test klase, dok se metode dekorisane sa [ClassCleanup] pozivaju nakon poslednjeg testa unutar klase:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[ClassInitialize]
public static void ClassInit(TestContext context)
{
	//...
}

[ClassCleanup]
public static void Cleanup()
{
	//...
}
&lt;/pre&gt;
&lt;p&gt;Ove metode inicijalizacije i cleanup se pozivaju pre i posle svake test metode. Pored toga, ovo su metode instance a ne staticke metode:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[TestInitialize]
public void TestInit()
{
}

[TestCleanup]
public void TestCleanup()
{
}
&lt;/pre&gt;
&lt;h2&gt;Prolaznost testova&lt;/h2&gt;
&lt;p&gt;Sam test može imati neko od nekoliko mogucih rezultata, odnosno statusa. Pored dva najbitnija, pro&amp;scaron;ao (passed) i pao (failed), test može imati i neodreden ishod (inconclusive) u slucaju da nismo u mogucnosti da procenimo da li je testirana funkcionalnost ispunjena. Pored ovih ishoda, testovi mogu imati i status obustavljen (aborted), neizvr&amp;scaron;en (not executed) i neizvr&amp;scaron;en do kraja usled isteka ocekivanog vremena trajanja (time out).&lt;/p&gt;
&lt;p&gt;Da bi test pro&amp;scaron;ao test metoda jednostavno ne sme da ispusti izuzetak. Ne postoji eksplicitni nacin da se kaže da je test pro&amp;scaron;ao, za razliku od ishoda pao (failed) i neodredenog ishoda (inconclusive).&lt;/p&gt;
&lt;p&gt;Za evaluaciju rezultata testova koristi se Assert klasa. Ona sadrži veliki broj metoda za proveru validnosti testa. Pomocu ovih metoda možemo proveriti da li kod koji testiramo generi&amp;scaron;e vrednost koju ocekujemo.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class Calculate
{
	public static int Add(int x, int y)
	{
		return (x + y);
	}
}

[TestClass]
public class UnitTest1
{
	private int x;
	private int y;

	[TestInitialize]
	public void Initialize()
	{
		var random = new Random(DateTime.Now.Millisecond);
		x = random.Next();
		y = random.Next();
	}

	[TestCleanup]
	public void Cleanup()
	{
	}

	[TestMethod]
	public void Add_Test()
	{
		var result = Calculate.Add(x, y);
		var expected = x + y;
		Assert.AreEqual(expected, result);
	}

	[TestMethod]
	public void Substract_Test()
	{
		Assert.Inconclusive("Method not implemented.");
	}
}
&lt;/pre&gt;
&lt;p&gt;Pored pomenutih atributa i metoda, Visual Studio Unit Testing framework sadrži jo&amp;scaron; mnogo toga, kao na primer, podr&amp;scaron;ku za DDT (Data Driven Testing), vi&amp;scaron;e o tome možete procitati u postu &lt;a href="../../../2011/4/data-driven-testing-xml-sqlce"&gt;Data Driven Testing - XML, SQLCE&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/W7QI_yGpodc" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/4/anatomija-test-klase</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/4/data-driven-testing-xml-sqlce</id><title type="text">Data Driven testing - XML, SQLCE</title><published>2011-04-17T22:24:00+02:00</published><updated>2011-04-17T22:24:00+02:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/sKJlQmSrL6E/data-driven-testing-xml-sqlce" /><content type="html">&lt;p&gt;Vrlo često se prilikom testiranja javlja potreba za izvr&amp;scaron;avanjem istog testa sa različitim ulaznim podacima. &amp;nbsp;Visual Studio Unit Testing Framework ima ugrađenu podr&amp;scaron;ku za Data Driven Testing (DDT).&lt;/p&gt;
&lt;p&gt;Data Driven testovi se razlikuju od ostalih testova po tome &amp;scaron;to su dekorisani sa DataSource atributom. Pomoću ovog atributa defini&amp;scaron;e se izvor ulaznih podataka. Izvor podataka može da bude CSV fajl, XML, SQL Server, SQLCE baza i slično. Kada se pokrene test, podaci se čitaju red po red, i test se izvr&amp;scaron;ava za svaki red posebno, a tekućem redu se pristupa preko TestContext-a.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[TestMethod]
[DataSource("System.Data.SqlClient",
"Data Source=.;Initial Catalog=TestData;Integrated Security=True;MultipleActiveResultSets=True",
"Table1", DataAccessMethod.Random)]
public void DDT_with_SQL()
{
   //
   // TODO: Add test logichere
   //
}

[TestMethod]
[DataSource("System.Data.SqlClient",
"Data Source=.;Initial Catalog=TestData;Integrated Security=True;MultipleActiveResultSets=True",
"MyView", DataAccessMethod.Sequential)]
public void DDT_with_SQL2()
{
   //
   // TODO: Add test logichere
   //
}&lt;/pre&gt;
&lt;p&gt;Ukoliko koristimo SQL Server kao izvor podataka, treba imati na umu da pri izvr&amp;scaron;avanju testova može da dođe do gubitka konekcije, &amp;scaron;to će izazvati pad testova. Takođe, može se desiti i da SQL Server na kome se nalaze ulazni podaci jednostavno nije dostupan računaru na kome želimo da izvr&amp;scaron;imo testove (recimo ako želimo da izvr&amp;scaron;imo testove na računaru klijenta).&lt;/p&gt;
&lt;p&gt;Pored toga, ponekad je potrebno promeniti ulazne podatke, te ukoliko baza ne poseduje neku vrstu history mehanizma ili backup, može se desiti da izgubimo vezu između prethodnih rezultata testova i ulaznih podataka.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[TestMethod]
[DeploymentItem(@"TestProject1\XMLFile1.xml")]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
"XMLFile1.xml", "DDT_with_XML", DataAccessMethod.Sequential)]
public void DDT_with_XML()
{
   //
   // TODO: Add test logic here
   //
}

[TestMethod]
[DeploymentItem(@"TestProject1\TestDatabase.sdf")]
[DataSource("System.Data.SqlServerCe.3.5",
"data source=|DataDirectory|\\TestDatabase.sdf;password=1234",
"Table1", DataAccessMethod.Sequential)]
public void DDT_with_SQLCE()
{
   //
   // TODO: Add test logic here
   //
}&lt;/pre&gt;
&lt;p&gt;Zbog toga je bolje koristiti XML ili SQLCE bazu kao izvor podataka kako bismo lak&amp;scaron;e mogli da vr&amp;scaron;imo deployment ulaznih podataka, kao i da ih sačuvamo zajedno sa rezultatima.&lt;/p&gt;
&lt;p&gt;Struktura XML fajla koji predstavlja DataSource testa:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;
&amp;lt;testsuite&amp;gt;
   &amp;lt;DDT_with_XML&amp;gt;
      &amp;lt;Year&amp;gt;2011&amp;lt;/Year&amp;gt;
      &amp;lt;Month&amp;gt;4&amp;lt;/Month&amp;gt;
      &amp;lt;Day&amp;gt;22&amp;lt;/Day&amp;gt;
      &amp;lt;Result&amp;gt;true&amp;lt;/Result&amp;gt;
   &amp;lt;/DDT_with_XML&amp;gt;
   &amp;lt;DDT_with_XML&amp;gt;
      &amp;lt;Year&amp;gt;2011&amp;lt;/Year&amp;gt;
      &amp;lt;Month&amp;gt;12&amp;lt;/Month&amp;gt;
      &amp;lt;Day&amp;gt;20&amp;lt;/Day&amp;gt;
      &amp;lt;Result&amp;gt;false&amp;lt;/Result&amp;gt;
   &amp;lt;/DDT_with_XML&amp;gt;
&amp;lt;/testsuite&amp;gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/sKJlQmSrL6E" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/4/data-driven-testing-xml-sqlce</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/3/timestamp-verzioniranje</id><title type="text">Timestamp verzioniranje</title><published>2011-03-26T21:19:00+01:00</published><updated>2011-03-26T21:19:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/srV7QaQljjg/timestamp-verzioniranje" /><content type="html">&lt;p&gt;Pre neki vikend za potrebe verzioniranja ove blog aplikacije napravio sam jednostavan alat. S obzirom da je u pitanju aplikacija na kojoj radim samo ja i koja se trenutno sastoji od jednog projekta, nisam imao potrebu ni za kakvim komplikovanim verzioniranjem, već mi je bila dovoljna verzija u vidu timestamp-a.&lt;/p&gt;
&lt;p&gt;Alat je krajnje jednostavan ali ba&amp;scaron; zbog toga mi se i sviđa. U pitanju je console aplikacija koja ažurira AssemblyInfo.cs fajl sa odgovarajućim formatom timestamp-a. Inicijalno je parsiranje argumenata re&amp;scaron;eno preko Linq-a, ali sam posle pretraživanja interneta prona&amp;scaron;ao jedan vrlo zgodan komad koda za te svrhe (&lt;a href="http://www.ndesk.org/Options"&gt;NDesk.Options&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Potrebno je proslediti DateTime formate za Major, Minor, Build i Version i alat će ažurirati AssemblyInfo.cs fajl. Pored ova 4 parametra, može se proslediti naziv i putanja do fajla koji sadrži verziju, ukoliko nije u pitanju podrazumevana putanja - Properties\AssemblyInfo.cs.&lt;/p&gt;
&lt;p&gt;Da bi automatizovali ovaj proces, potrebno je u pode&amp;scaron;avanjima projekta podesiti Pre-build event na sledeći način:&lt;/p&gt;
&lt;p&gt;"C:\Tools\Versioner.exe" /M=yyyy /m=MM /b=dd /r=HHmm /a="$(ProjectDir)Properties\AssemblyInfo.cs"&lt;/p&gt;
&lt;p&gt;Ova komanda će pri svakom build-u automatski ažurirati verziju. Ukoliko vam ne odgovara ovakav format, može se proslediti bilo koji string koji je validan za formatiranje DateTime vrednosti. Interno za svaki od prosleđenih argumenata (Major, Minor, Build i Version), poziva se DateTime.Now.ToString(versionFormat). Na kraju jo&amp;scaron; da napomenem da nije potrebno sve argumente proslediti već samo one koje želte da ažurirate. Nadam se da će jo&amp;scaron; nekome ovo koristiti.&lt;/p&gt;
&lt;p&gt;Alat možete preuzeti &lt;a href="http://download.ivanfranjic.net/Versioner.zip"&gt;ovde&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/srV7QaQljjg" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/3/timestamp-verzioniranje</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/3/asp.net-mvc-vs-asp.net-webforms</id><title type="text">ASP.NET MVC vs ASP.NET WebForms</title><published>2011-03-23T22:11:00+01:00</published><updated>2011-03-23T22:11:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/W1aWfrtAbEM/asp.net-mvc-vs-asp.net-webforms" /><content type="html">&lt;p&gt;ASP.NET MVC se pojavio u martu 2009. godine i većina članaka na temu ASP.NET MVC vs ASP.NET WebForms datira iz te godine. Međutim, ASP.NET MVC je pre&amp;scaron;ao veliki put od tada i danas je dostupan u verziji 3.0. Mislim da će ovaj članak najvi&amp;scaron;e koristiti onima koji tek počinju sa izučavanjem web tehnologija.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;h3&gt;Prednosti ASP.NET WebForms-a&lt;/h3&gt;
&lt;p&gt;Kada se govori o prednostima WebForms-a, ono &amp;scaron;to većina članaka ističe jeste da je to zrela tehnologija sa bogatim izborom serverskih kontrola. Ovo polako prestaje da bude prednost WebForms-a, jer je sve vi&amp;scaron;e kontrola/helpera za ASP.NET MVC. Kao primer, pomenuću &lt;a href="http://www.telerik.com/products/aspnet-mvc.aspx"&gt;Telerik&lt;/a&gt;-ov odličan set ASP.NET MVC kontrola, koji ne samo da su istog kvaliteta kao i set kontrola za ASP.NET WebForms već su ove kontrole i besplatne.&lt;/p&gt;
&lt;p&gt;ViewState mehanizam se pominje i kao prednost i kao mana WebForms-a. Ovaj mehanizam je odgovoran za čuvanje stanja, u vidu skrivenih polja web strane, i prenos tog stanja između klijenta i servera. Međutim, u nekim slučajevima ViewState može da bude jako velik, kao npr. kod GridView kontrole. Naravno, ViewState sa može ograničiti ili isključiti, ali time uklanjamo mogućnost da kontrole imaju stanje.&lt;/p&gt;
&lt;p&gt;Pored ovog problema, ViewState može negativno da utiče na rangiranje stranice kod pretraživača. Neki pretraživači uzimaju u obzir koliko je neka ključna reč blizu početka stranice, a ViewState može da potisne ključnu reč niže.&lt;/p&gt;
&lt;p&gt;Zbog toga kako WebForms apstrahuje web development, developeri imaju manje kontrole nad HTML-om i načinom na koji klijent komunicira sa serverom. U dana&amp;scaron;nje vreme, činjenica da WebForms apstrahuje HTTP i HTML vi&amp;scaron;e ne predstavlja prednost, jer otežava kompatibilnost sa različitim browser-ima kao i integraciju sa nekim od JavaScript frameworka.&lt;/p&gt;
&lt;h3&gt;Prednosti ASP.NET MVC frameworka&lt;/h3&gt;
&lt;p&gt;ASP.NET MVC framework je zasnovan na MVC arhitekturnom obrascu, koji se pokazao kao pogodan za web aplikacije. Ovaj obrazac razdvaja aplikaciju na tri celine koje se mogu relativno nezavisno menjati, čime se podiže jednostavnost održavanja aplikacije.&lt;/p&gt;
&lt;p&gt;ASP.NET MVC je zami&amp;scaron;ljen tako da bude lak za testiranje i ovo je jedna od osobina MVC frameworka koja sve vi&amp;scaron;e dobija na značaju. Pored toga, postoji i ugrađena podr&amp;scaron;ka za dobre prakse kao &amp;scaron;to su &lt;a href="http://en.wikipedia.org/wiki/Dependency_injection"&gt;Dipendency Injection&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;S obzirom da se ne koriste serverske kontrole, developeri imaju potpunu kontrolu nad HTML-om i jednostavnija je integracija sa frameworkom kao &amp;scaron;to je npr. &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;. Bogati korisnički interfejs se može realizovati pomoću &lt;a href="http://jqueryui.com/"&gt;jQuery UI&lt;/a&gt; frameworka.&lt;/p&gt;
&lt;p&gt;Sam framework je napravljen tako da postoji mnogo tačaka za pro&amp;scaron;irenje i upotrebu alternativnih komponenti. ASP.NET MVC dolazi uz dva mehanizma za generisanje pogleda, ali podržava i upotrebu third party mehanizama za generisanje pogleda.&lt;/p&gt;
&lt;p&gt;U nekim člancima se pominje URL rutiranje kao prednost ASP.NET MVC frameworka u odnosu na WebForms. Ovo nije tačno, jer rutiranje ne predstavlja funkcionalnost MVC frameworka, već je to deo ASP.NET-a, &amp;scaron;to znači da se može koristiti i za WebFroms aplikacije.&lt;/p&gt;
&lt;h3&gt;Zaključak&lt;/h3&gt;
&lt;p&gt;WebForms je zasnovan na događajima, &amp;scaron;to nam omogućava gotovo isti način razvoja kao i desktop aplikacija. Ovakav način razvoja je s razlogom odabran kako bi Visual Basic developeri mogli brzo i lako da pređu na web development. Vi&amp;scaron;e o ovome možete pročitati u članku &lt;a href="../../2011/3/asp-net-mvc-framework"&gt;ASP.NET MVC framework&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;S druge strane, MVC zamenjuje događaje sa akcijama kontrolera. Glavne prednosti MVC frameworka su jasna podela odgovornosti, lak&amp;scaron;e testiranje i veća kontrola nad HTML-om. Za razliku od WebForms-a, MVC ne koristi Viewstate, Postback niti serverske kontrole.&lt;/p&gt;
&lt;p&gt;Pre gotovo godinu i po dana, odlučio sam da počnem sa izučavanjem web tehnologija i tada sam se suočio sa izborom između ove dve tehnologije. Odabrao sam MVC, i dalje mislim da je to pravi izbor. &amp;Scaron;ta vi mislite? &amp;Scaron;ta ćete vi odabrati?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/W1aWfrtAbEM" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/3/asp.net-mvc-vs-asp.net-webforms</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/3/compile-time-view-checking</id><title type="text">Compile-time view checking</title><published>2011-03-18T20:09:00+01:00</published><updated>2011-03-18T20:09:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/41fWm78FBK8/compile-time-view-checking" /><content type="html">&lt;p&gt;Prilikom razvoja web aplikacija, pogledi (views) su deo aplikacije koji se najče&amp;scaron;će menjaju. Vrlo lako se može napraviti slovna gre&amp;scaron;ka koja može da poremeti prikaz celog pogleda. Sam kod koji se nalazi u pogledu, se ne kompajlira sve dok IIS ne poku&amp;scaron;a da renderuje pogled.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Sigurno se i vama desilo da izmenite neki Html helper, možda samo potpis metode, a da ne izmenite sve pozive ovog helpera u pogledima koji ga koriste. Ovo dovodi do pucanja stranice u neočekivanim trenutcima, možda par dana nakon izmene, nakon &amp;scaron;to ste i zaboravili da ste menjali Html helper.&lt;/p&gt;
&lt;p&gt;Na svu sreću, postoji način da Visual Studio kompajlira poglede prilikom builda aplikacije. Međutim, ova funkcionalnost nije podržana kroz GUI, već je potrebno izmeniti .csproj fajl.U okviru .csproj fajla, koji se može otvoriti pomoću nekog xml editora, ili običnog text editora, nalazi se MvcBuildViews element, čije je podrazumevano pode&amp;scaron;avanje false i treba ga podesiti na true. Nakon &amp;scaron;to se sačuva ova izmena, Visual&amp;nbsp;Studio će kompajlirati poglede prilikom svakog builda.&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;MvcBuildViews&amp;gt;true&amp;lt;/MvcBuildViews&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Nažalost, ovo je potrebno podesiti ručno za svaki novi projekat, a pored toga povećava compile-time i do nekoliko puta (u zavisnosti koliko pogleda ima). Re&amp;scaron;enje je da se compile-time view checking opcija uključi za Release konfiguraciju builda. &amp;Scaron;to se može postići definisanjem MvcBuildViews elementa u PropertyGroup-i koja ima odgovarajući uslov.&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "&amp;gt;
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/41fWm78FBK8" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/3/compile-time-view-checking</feedburner:origLink></entry><entry><id>http://www.ivanfranjic.net/2011/3/asp-net-mvc-framework</id><title type="text">ASP.NET MVC framework</title><published>2011-03-17T23:49:00+01:00</published><updated>2011-03-17T23:49:00+01:00</updated><link rel="alternate" href="http://feedproxy.google.com/~r/IvanFranjic/Atom/~3/dXKfHtOUo3U/asp-net-mvc-framework" /><content type="html">&lt;p&gt;MVC obrazac je prvi put opisan jo&amp;scaron; 1979. godine. od strane &lt;a href="http://en.wikipedia.org/wiki/Trygve_Reenskaug"&gt;Trygve Reenskaug&lt;/a&gt;, međutim, negovoj popularnosti u razvoju web aplikacija najvi&amp;scaron;e je doprineo &lt;a href="http://en.wikipedia.org/wiki/Ruby_on_Rails"&gt;Ruby on Rails&lt;/a&gt;. Iako je MVC obrazac bio poznat i ranije, prelomna tačka je bila negde sredinom 2004. godine kada je prezentovan Ruby on Rails framework. U ovom frameworku spojene su mogućnosti Ruby jezika i MVC obrazca kako bi se stvorilo ne&amp;scaron;to posebno.&lt;/p&gt;
&lt;p&gt;&lt;!-- Summary Break --&gt;&lt;/p&gt;
&lt;p&gt;Ruby on Rails je definitivno jedan od najpopularnijih MVC frameworka za web, i on je zasnovan na dva osnovna principa: &lt;a href="http://en.wikipedia.org/wiki/Convention_over_configuration"&gt;Convention over configuration&lt;/a&gt; i &lt;a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY&lt;/a&gt; princip. Danas postoji veliki broj MVC frameworka u gotovo svim programskim jezicima, i svi oni su zasnovani na ova dva osnovna principa, pa tako i ASP.NET MVC.&lt;/p&gt;
&lt;p&gt;Osnovna ideja MVC obrazca je razdvajanje domenske logike (model - Model) i korisničkog interfejsa (pogled - View). Ova dva dela su indirektno povezana preko Publish-Subscribe mehanizma poznatog i kao &lt;a href="http://en.wikipedia.org/wiki/Observer_pattern"&gt;Observer&lt;/a&gt; obrazac. Treći deo arhitekture predstavlja kontroler (Controller) koji implementira konkretnu strategiju (&lt;a href="http://en.wikipedia.org/wiki/Strategy_pattern"&gt;Strategy&lt;/a&gt;) za pogled.&lt;/p&gt;
&lt;p&gt;Primena ovog obrazca ima smisla kada je pogled jednostavan i ne sadrži programski kod, kao &amp;scaron;to je to kod web aplikacija i HTML-a. Na ovaj način, pogled kreira korisnički interfejs, a kontroler obraduje korisničke akcije.&lt;/p&gt;
&lt;p&gt;Davne 2002. godine pojavio se .Net framework, a sa njim i ASP.NET. Do tada su desktop developeri koristili Visual Basic, a web developeri klasičan ASP. ASP je bio jednostavan skript jezik, dok je s druge strane VB imao kompletnije razvojno okruženje sa jednostavnim drag-and-drop konceptom kreiranja formi.&lt;/p&gt;
&lt;p&gt;S obzirom da je do tada Microsoft stvorio armiju VB developera, logicno je bilo za očekivati da ce se nacin razvoja desktop aplikacija preneti i na web aplikacije. Zbog toga je uz ASP.NET do&amp;scaron;ao WebForms, koji je zasnovan na događajima i obezbeđuje isti način razvoja (drag-and-drop) kao i kod WinForms aplikacija.&lt;/p&gt;
&lt;p&gt;U WebForms je uloženo dosta truda kako bi se apstrahovao stateless medij kakav je web. Ovo je naravno imalo svoju cenu, ali se tada smatralo da je važnija produktivnost i vrlo strma kriva učenja. Vremenom je postalo jasno da ovakav princip razvoja nije pogodan za web aplikacije.&lt;/p&gt;
&lt;p&gt;ASP.NET MVC framework predstavlja implementaciju MVC obrazca za .Net jezike. Posle niza godina, Microsoft je uvideo da razvoj web apliakcija zasnovan na dogadajima nije prikladan za web, i da developeri žele vi&amp;scaron;e kontrole nad svojim kodom. Kao rezultat toga, pokrenut je open-source projekat razvoja ASP.NET MVC frameworka koji Microsoft vodi uz veliku pažnju &amp;scaron;ta programerska zajednica želi.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IvanFranjic/Atom/~4/dXKfHtOUo3U" height="1" width="1"/&gt;</content><feedburner:origLink>http://www.ivanfranjic.net/2011/3/asp-net-mvc-framework</feedburner:origLink></entry></feed>
