Gunnar Peipman's ASP.NET blog

ASP.NET, C#, SharePoint, SQL Server and general software development topics.

Sponsors

News

 
 
 
DZone MVB

Links

Social

October 2010 - Posts

What is Visual Studio Async?

Anders Hejlsberg @ PDC10During PDC10 Anders Hejlsberg announced Visual Studio Async CTP when speaking about new stuff in C# and VB.NET next versions. In this posting I will introduce the background of Visual Studio Async and I will provide you with links to different resources so you can get started immediately.

Why Visual Studio Async?

The main point of Visual Studio Async is to simplify asynchronous programming. If you have ever wrote some asynchronous code you know very well that it is more complex than synchronous code. And it is also longer. Instead of calling simple method using one line we have to write method that initializes asynchronous call and then we have to write callback that is called when asynchronous code has completed the work it got to do.

Smarter ones of you have also thought many times that there should be some patterns because what we are doing when writing asynchronous code that solves different problems has still some similarities. Slowly, step by step, we are now getting to the point where complexities of asynchronous code are solved by compiler and we can write asynchronous code almost like synchronous one.

How we got to Visual Studio Async?

When something new comes out it is always good to know some historical background to get better idea about what’s going on. Here is the timeline of C# and VB.NET.

.NET Framework timeline

The roots of Visual Studio Async are in parallel computing stuff that came after LINQ. We got parallel extensions for LINQ (PLINQ) and Task Parallel Library (TPL) when .NET Framework 4.0 came out. Task<T> is one of the main building blocks of Visual Studio Async and if you have used Task<T> before then you should be very familiar with all the backgrounds of Visual Studio Async. As .NET Framework has now all the features that enable to make asynchronous processing easier for us then Visual Studio Async will be the solution.

Requirements

To install and use Visual Studio Async your technical environment must meet the following requirements to operating system and Visual Studio:

  • Operating system: Windows 7, Windows Server 2003, Windows Server 2008, Windows Vista, or Windows XP
  • Visual Studio: Professional, Premium, or Ultimate (English-US version)

Samples

After installer of Visual Studio Async is completed you get the following page opened.

Visual Studio Async Samples

You can select examples, open them in Visual Studio and run them to see how they are written and how they work. I suggest you to start with example called 101 Asyncs. It illustrates you nicely how things are done on .NET 4.0 and how same things can be done on Visual Studio Async. Take a careful look at the following screenshot – there is Run Sample button. Yes, you can run all these samples right in the sample explorer.

101 Asyncs Sample Application

Comparing .NET 4.0 and Visual Studio Async Code

Let’s see now how is the same code implemented on .NET 4.0 and how it looks like on Visual Studio Asyc. .NET 4.0 version is here.


public void AsyncIntroSerialBefore()
{
    var client = new WebClient();
 
    client.DownloadStringCompleted += DownloadStringCompleted_1;
    client.DownloadStringAsync(new Uri("http://www.weather.gov"));
}
 
void DownloadStringCompleted_1(object sender, DownloadStringCompletedEventArgs e)
{
    WriteLinePageTitle(e.Result);
 
    var client = new WebClient();
 
    client.DownloadStringCompleted += DownloadStringCompleted_2;
    client.DownloadStringAsync(new Uri("http://www.weather.gov/climate/"));
}
 
void DownloadStringCompleted_2(object sender, DownloadStringCompletedEventArgs e)
{
    WriteLinePageTitle(e.Result);
 
    var client = new WebClient();
 
    client.DownloadStringCompleted += DownloadStringCompleted_3;
    client.DownloadStringAsync(new Uri("http://www.weather.gov/rss/"));
}
 
void DownloadStringCompleted_3(object sender, DownloadStringCompletedEventArgs e)
{
    WriteLinePageTitle(e.Result);
}

And here is the same code written on Visual Studio Async.


public async void AsyncIntroSerial()
{
    var client = new WebClient();
 
    WriteLinePageTitle(await client.DownloadStringTaskAsync(
new Uri(http://www.weather.gov))
);
    WriteLinePageTitle(await client.DownloadStringTaskAsync(
new Uri(http://www.weather.gov/climate/))
);
    WriteLinePageTitle(await client.DownloadStringTaskAsync(
new Uri(http://www.weather.gov/rss/))
);
}

When you remove these WriteLinePageTitle calls the method body is about 5 lines and it is easy to read.

Resources

Posted: Oct 30 2010, 06:18 PM by DigiMortal | with 8 comment(s)
Filed under: ,
ASP.NET MVC 3: Building simple image editor using WebImage helper

In my previous posting about WebImage helper I introduced how to use WebImage for different image manipulations. In this posting I will show you how to build simple online image editor using WebImage helper.

Source code

You can find source code of this example from Visual Studio 2010 experiments repository at GitHub.

Source code @ GitHub Source code repository
GitHub

Simple image editor belongs to Experiments.AspNetMvc3NewFeatures solution, project name is Experiments.AspNetMvc3NewFeatures.Aspx.

Here you can see the screenshot of simple image editor.

Simple WebImage editor

Four simple operations is enough for current example.

Building editor view

Before going to controller that is extremely simple – believe me, it is no-brainer – let’s take a look at view. The editor is made up from following parts:

  • image tag that shows image with current effects,
  • effects checkboxes,
  • JavaScript that requests image with selected effects from server.

Here is the view.


<%@ Page Title="Image Worksop" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Image Workshop
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">   
    <script type="text/javascript">
        function updateImage() {
            var req = '/ImageWorkshop/GetImage?';
            var query = '';

            if ($('#HorizontalFlip').is(':checked'))
                query += '&HorizontalFlip=1';
            if ($('#VerticalFlip').is(':checked'))
                query += '&VerticalFlip=1';
            if ($('#RotateLeft').is(':checked'))
                query += '&RotateLeft=1';
            if ($('#RotateRight').is(':checked'))
                query += '&RotateRight=1';

            req += query.substr(1);
            $('#image').attr("src", req);
        }
    </script>

    <h2>Image Workshop</h2>

    <% using(Html.BeginForm()) { %>
        <table border="0" cellpadding="0" cellspacing="5">
        <tr>
        <td valign="top" rowspan="10">
            <img src="/ImageWorkshop/GetImage"  id="image" alt="" />
        </td>
        <td valign="middle"><input type="checkbox" id="HorizontalFlip" value="1" />
  Flip horizontally</td>
        </tr>
        <tr>
        <td valign="middle"><input type="checkbox" id="VerticalFlip" value="true" />
  Flip vertically</td>
        </tr>
        <tr>
        <td valign="middle"><input type="checkbox" id="RotateLeft" value="true" />
  Rotate left</td>
        </tr>
        <tr>
        <td valign="middle"><input type="checkbox" id="RotateRight" value="true" />
  Rotate right</td>
        </tr>
        <tr>
        <td><input type="button" value="Preview" onclick="updateImage()" /></td>
        </tr>
        </table>
    <% } %>
</asp:Content
>

The JavaScript function updateImage() checks what checkboxes are checked and creates query string for GetImage controller action. This query string contains values only for applied effects.

Controller actions

When you take a look at image definition in view you can see that we need two separate actions – one that returns editor view and the other that returns image. I said before that controller is extremely simple. Don’t mind my not so nice solution for image action – it is my working draft.


public class ImageWorkshopController : Controller
{
    [HttpGet]
    public ActionResult Index()
    {
        return View();
    }
 
    public void GetImage(string horizontalFlip="", string verticalFlip="",
                        string rotateLeft="", string rotateRight="")
    {
        var imagePath = Server.MapPath("~/images/bunny-peanuts.jpg");
        var image = new WebImage(imagePath);
 
        if (!string.IsNullOrWhiteSpace(verticalFlip))
            image = image.FlipVertical();
        if (!string.IsNullOrWhiteSpace(horizontalFlip))
            image = image.FlipHorizontal();
        if (!string.IsNullOrWhiteSpace(rotateLeft))
            image = image.RotateLeft();
        if (!string.IsNullOrWhiteSpace(rotateRight))
            image = image.RotateRight();
 
        image.Write();
    }
}

Applying effects to image is very easy. We just check the values sent from view and apply the effect only if appropriate value is not null or empty string. That’s why I created query string with effect values as ones ("1") in JavaScript.

ASP.NET MVC 3: Using global action filters to find out running time of controller actions

Lately I blogged about global action filters in ASP.NET MVC 3. Yesterday I found cool article from Nick Berardi’s Coder Journal where he introduces how to use action filters to measure running time of ASP.NET MVC controllers. And here is my experiment – how to use global action filters to find out how long controller actions are running. You just need couple of lines of code.

Source code

You can find source code of this example from Visual Studio 2010 experiments repository at GitHub.

Source code @ GitHub Source code repository
GitHub

Example is located in Experiments.AspNetMvc3NewFeatures.GlobalActionFilters project.

StopwatcherAttribute class by Nick Berardi

To take time Nick uses StopwatchAttribute class that you can find from his GitHub repository. I paste this class also here so you can take a look at it without leaving this page. I made some modifications so you can use this class also with ASP.NET development web server.


public class StopwatchAttribute : ActionFilterAttribute
{
    private readonly Stopwatch _stopwatch;
 
    public StopwatchAttribute()
    {
        _stopwatch = new Stopwatch();
    }
 
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _stopwatch.Start();
    }
 
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        _stopwatch.Stop();
 
        var httpContext = filterContext.HttpContext;
        var response = httpContext.Response;
        var elapsed = _stopwatch.Elapsed.ToString();
 
        // Works for Cassini and IIS
        //response.Write(string.Format("<!-- X-Stopwatch: {0} -->", elapsed));  
 
        // Works for IIS
        response.AddHeader("X-Stopwatch", elapsed);
    }
}

Now let’s take default controller that is created when you create a new ASP.NET MVC web application.


public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewModel.Message = "Welcome to ASP.NET MVC!";
 
        return View();
    }
 
    public ActionResult About()
    {
        return View();
    }
}

We will add nothing to this code by ourselves. We leave it like it is. One thing we have to do is we have to modify our application class in Global.asax.cs.


protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
 
    GlobalFilters.Filters.Add(new StopwatchAttribute());
 
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

Okay, now it’s the moment of truth. Let’s see what ASP.NET MVC outputs when we request default page and About page. For both pages you should see something like this in page source.

Output of StopwatchAttribute

If you have controller actions that output something other than HTML you cannot write output of StopwatchAttribute class to response – use headers instead of response body.

Conclusion

Global action filters provided by ASP.NET MVC 3 are powerful tools. When working on IIS we can easily make our requests to be easily measured using StopwatchAttribute class when we register it as a global action filter and let it write it’s output to response headers. Tools like Firebug and Fiddler2 allow you to monitor HTTP traffic easily and it is not hard to read headers if you have some of these tools.

Deploying ASP.NET MVC 3 web application to server where ASP.NET MVC 3 is not installed

When I wrote my last posting about jQuery Mobile and ASP.NET MVC. I built my sample application on ASP.NET MVC 3. To try it out with friends I put my application up to my web server where I don’t have ASP.NET MVC 3 installed. In this posting I will tell you what files you need and where you can find them.

Here are the files I had to upload to get my application running on server where ASP.NET MVC 3 is not installed.

ASP.NET MVC 3 files

You can change reference to System.Web.Helpers.dll to be the local one so it is copied to bin folder of your application. First file in this list is my web application dll and you don’t need it to get ASP.NET MVC 3 running. All other files are located at the following folder:

C:\Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies\

If there are more files needed in some other scenarios then please leave me a comment here. And… don’t forget to convert the folder in IIS to application.

Posted: Oct 27 2010, 11:36 AM by DigiMortal | with 7 comment(s)
Filed under: , ,
Building mobile web site with ASP.NET MVC and jQuery Mobile

jQuery Mobile is unified UI system that will work on all popular mobile device platforms. Currently alpha version is available to download. In this posting I will show you how to use jQuery Mobile with ASP.NET MVC 3 and how jQuery Mobile pages look on Windows Mobile.

Source code

You can find source code of this example from Visual Studio 2010 experiments repository at GitHub.

Source code @ GitHub Source code repository
GitHub

Example is located in Experiments.MobileWeb.JqueryMobile project.

Anatomy of jQuery Mobile page

JQuery Mobile pages are made up of div tags that have data-role attribute. Data-role attribute tells jQuery Mobile what is the intended use of given div so it can add styles and modify mark-up inside the div to make it look cool. Here is the basic jQuery Mobile page.


<!DOCTYPE html> 
<html> 
<head> 
<title>Page Title</title> 
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a1/jquery.mobile-1.0a1.min.css" />
<script src="http://code.jquery.com/jquery-1.4.3.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0a1/jquery.mobile-1.0a1.min.js"></script
>
</
head> 
<body> 

<div data-role="page">

<div data-role="header">
<h1>Page Title</h1>
</div><!-- /header -->

<div data-role="content">
<p>Page content goes here.</p>
</div><!-- /content -->

<div data-role="footer">
<h4>Page Footer</h4>
</div><!-- /header -->
</div><!-- /page -->

</body
>
</
html
>

Page is divided to smaller pages – and one of them is shown at time. I see here some analogy with WML and cards. Like said before, data-role specifies what is the role of div. You can see from HTML above that page contains header, content and footer divs. All these dives get nice and cool face automagically like we see later.

Master page

We will start with default MVC project where all unnecessary stuff is cleaned out. I don’t have scripts in my project, instead I will include them from jQuery CDN. I added one additional content place holder for page title that is shown on the upper part of device screen. I also added all necessary divs for this example. Here is my master page.


<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<!DOCTYPE html
>
<
html
>
<
head id="Head1" runat="server">
    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a1/jquery.mobile-1.0a1.min.css" />
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.3.min.js"></script>
    <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a1/jquery.mobile-1.0a1.min.js"></script
>
</
head>

<body
>
<
div data-role="page">
    <div data-role="header">
        <h1><asp:ContentPlaceHolder ID="PageTitleContent" runat="server" /></h1>
    </div>
    <div data-role="content">
        <asp:ContentPlaceHolder ID="MainContent" runat="server" />
    </div>
    <div data-role="footer" class="ui-bar">
        <%: Html.ActionLink("About", "About", "Home"%>
    </div
>
</
div
>
</
body
>
</
html
>

You can also add separate content place holder for footer if you like. Although I have simple place holders system here you can still build more complex templates if you need.

Default page

Now we have master page. Let’s put up default page for example site.


<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Beer Index
</asp:Content>

<asp:Content ID="Content3" ContentPlaceHolderID="PageTitleContent" runat="server">
Beer Index
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
<li><%: Html.ActionLink("Heineken", "Heineken", "Home") %></li>
<li><%: Html.ActionLink("Amstel", "Amstel", "Home"%></li>
</ul>

</asp:Content
>

This is the page on Google Chrome.

jQuery Mobile: Beer Index on Chrome

Seems like nice fit for devices with black cover and dark user interface. And what’s the best -I had to do almost nothing to get done with this beautiful UI.

Pages on mobile

Here are the best results I got on my HTC Touch 2. You can see how Opera Mobile 10 shows our pages. Everything looks pretty okay for alpha version. The only bug you can see here is on the title of left screenshot. But my information view about Amstel is very okay.

jQuery Mobile: Beer Index on Opera Mobile 10 jQuery Mobile: Amstel on Opera Mobile 10

What about Internet Explorer? Well, nothing … it is listed as “C – Low Quality” browser that is not capable of utilizing media queries. What it means? Well, plain HTML with default styles that browser provides. Yeah, good old Times New Roman based pages and what is most scary – IE for Windows Phone 7 is listed as C browser too. I still hope that IE that ships with Windows Phone 7 is modern browser and ready for jQuery.

Conclusion

Mobile web is starting getting popular and hopefully this time revolution happens as devices are able to provide better user experience than before and we can use fast mobile internet connections. Mobile browsers have worse compatibility with each other than usual web browsers and jQuery Mobile seems to be the long waited tool that helps easily get over those problems. There are more component available for mobile browser UI-s and I suggest you to take a look at what jQuery Mobile has to offer. I think that something great is happening. :)

SQL Server: How to insert million numbers to table fast?

Yesterday I attended at local community evening where one of the most famous Estonian MVPs – Henn Sarv – spoke about SQL Server queries and performance. During this session we saw very cool demos and in this posting I will introduce you my favorite one – how to insert million numbers to table.

The problem is: how to get one million numbers to table with less time? We can solve this problem using different approaches but not all of them are quick. Let’s go now step by step and see how different approaches perform.

NB! The code samples here are not original ones but written by me as I wrote this posting.

Using WHILE

First idea for many guys is using WHILE. It is robust and primitive approach but it works if you don’t think about better solutions. Solution with WHILE is here.


declare @i as int
set
 @i = 0

while(@i < 1000000)
begin
   
    
insert into numbers values(@i)
    set @i += 1
end

When we run this code we have to wait. Well… we have to wait couple of minutes before SQL Server gets done. On my heavily loaded development machine it took 6 minutes to run. Well, maybe we can do something.

Using inline table

As a next thing we may think that inline table that is kept in memory will boost up performance. Okay, let’s try out the following code.


declare @t TABLE (number int)
declare @i as 
int
set
 @i = 0

while(@i < 1000000)
begin
   
    
insert into @t values(@i)
    set @i += 1
end

insert
 into numbers select * from @t

Okay, it is better – it took “only” 01:30 to run. It is better than six minutes but it is not good yet. Maybe we can do something more?

Optimizing WHILE

If we investigate the code in first example we can find one hidden resource eater. All these million inserts are run in separate transaction. Let’s try to run inserts in one transaction.


declare @i as int
set
 @i = 0

begin 
transaction
while
(@i < 1000000)
begin
   
    
insert into numbers values(@i)
    set @i += 1
end
commit
 
transaction

Okay, it’s a lot better – 18 seconds only!

Using only set operations

Now let’s write some SQL that doesn’t use any sequential constructs like WHILE or other loops. We will write SQL that uses only set operations and no long running stuff like before.


declare @t table (number int)
insert into
 @t 
    
select 0
    union
 all
    
select 1
    union
 all
    
select 2
    union
 all
    
select 3
    union
 all
    
select 4
    union
 all
    
select 5
    union
 all
    
select 6
    union
 all
    
select 7
    union
 all
    
select 8
    union
 all
    
select 9

insert into
 numbers
    
select
        t1.number + t2.number*10 + t3.number*100 +
 
        t4.
number*1000 + t5.number*10000 + t6.number*100000
    from
        @t as
 t1, 
        @t 
as
 t2,
        @t 
as
 t3,
        @t 
as
 t4,
        @t 
as
 t5,
        @t 
as t6

Bad side of this SQL is that it is not as intuitive for application programmers as previous examples. But when you are working with databases you have to know how some set calculus as well. The result is now seven seconds!

Results

As last thing, let’s see the results as bar chart to illustrate difference between approaches.

Results: How to get million numbers to table?

I think this example shows very well how usual optimization can give you better results but when you are moving to sets – this is something that SQL Server and other databases understand better – you can get very good results in performance.

ASP.NET MVC 3 Beta: Using WebMail helper to send e-mail

This far I have blogged about WebImage and Chart helpers. Now let’s see another new helper – WebMail – that you can easily use to send e-mails. WebMail is easy to configure and extremely easy to use. In this posting I will show you simple feedback form that uses WebMail to send feedback messages.

Source code

You can find source code of this example from Visual Studio 2010 experiments repository at GitHub.

Source code @ GitHub Source code repository
GitHub

Example is located in Experiments.AspNetMvc3NewFeatures.Razor project.

Feedback view

As a first thing let’s create view for feedback form. I am using Razor view engine in this posting. Feedback view is really simple. It contains fields that user must fill and validation message that is shown when something is wrong.


@model dynamic
 
@{
    View.Title = "Feedback";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
    <h2>Feedback</h2>
 
    <p>@Html.ValidationMessage("_FORM")</p>
 
    @using(Html.BeginForm()) {
        <table>
        <tr>
            <td>Your e-mail:</td>
            <td>@Html.TextBox("email")</td>
        </tr>
        <tr>
            <td>Subject:</td>
            <td>@Html.TextBox("subject")</td>
        </tr>
        <tr>
            <td>Body:</td>
            <td>@Html.TextArea("body")</td>
        </tr>
        </table>
        <input type="submit" value="Send" />
    }

To be honest I have used no validation in this example. Validation message for _FORM is used to show exceptions when something went wrong. It makes it easier for you to play with this example.

This is our feedback form

Sending e-mail using WebMail

Before we start sending e-mail I show you two controller actions. There actions are used to show feedback form and page that is shown when e-mail is successfully sent.


[HttpGet]
public ActionResult Feedback()
{
    return View();
}
public ActionResult FeedbackSent()
{
    return View();
}


I have shown no FeedbackSent view here. I am very sure you are able to create this simple view by yourselves. :)

Now let’s take a look at controller action that uses WebMail to send e-mail. Notice how I can easily use SmtpServer static property to set the address of SMTP server. There are more static properties that let you configure WebMail helper. In the case of exception the exception is shown on feedback form with stack trace. If e-mail is sent without errors then user is redirected to FeedbackSent view where he or she can read some bla-bla-bla about when answer is expectedly sent and so on.


[HttpPost]
public ActionResult Feedback(string email, string subject, string body)
{            
    try
    {
        WebMail.SmtpServer = "my.smtp.server";
        WebMail.Send(
                "feedback[at]mycompany.domain",
                subject,
                body,
                email
            );
 
        return RedirectToAction("FeedbackSent");
    }
    catch (Exception ex)
    {
        ViewData.ModelState.AddModelError("_FORM", ex.ToString());
    }
 
    return View();
}

And now let’s take a look what’s going on in my mailbox where I sent my test messages.

Test e-mails in my Live mailbox

Mission completed – seems like I can go to sleep now. :)

By the way, if you don’t specify sender when calling WebMail.Send() method then e-mail is sent out from DoNotReply@localhost address.

ASP.NET MVC 3 Beta: Razor views support comments now

Sometimes we need server-side comments in ASP.NET MVC views. New version of Razor view engine supports comments in views and in this posting I will show you example of view with multiline comments.

I will use the view from my ASP.NET MVC charts caching example and add one multiline comment to this view. Note that comments are put between @* and *@ marks.


@{
    View.Title = "Home Page";
}
 
<h2>@View.Message</h2>
<p>
    @* 
        Charts area 
        -----------
        1. cached for 10 minutes by default
        2. cached for 180 minutes
    *@
    <img src="/Home/MyChart" />
    <img src="/Home/MyCachedChart" />
</p>

NB! This is only example. Don’t write long stories to the comments of your views. Add comments only if it is necessary and if it helps UI developers to communicate better with the presentation layer or model.

ASP.NET MVC 3 Beta: Simple image manipulations using WebImage helper

First new helper in ASP.NET MVC 3 Beta I blogged about was chart helper. In this posting I will introduce you another cool helper that is called WebImage and that provides you with image manipulation functions. Also this helper is made for web and instead of messing with more complex GDI+ functions you can do a lot of stuff with images very easily.

Source code

You can find source code of this example from Visual Studio 2010 experiments repository at GitHub.

Source code @ GitHub Source code repository
GitHub

Sample application demonstrates all the transformations that WebImage can do and you can use my solution to play with WebImage and see how it works. You can find all image stuff from ImageController and related views.

OMG! Bunny is flipped!
Click on image to see it at original size.

Feel free to download and play with it! :)

WebImage helper class

WebImage helper class let’s you show images in controller actions similarly to chart helper. Here you can see one very simple controller action that displays image.


public void GetImage()
{
    new WebImage(ImagePath)
        .Write();
}

Note that controller action does not return result. It clears response, and writes image correctly into it. After that content is sent to client and response ends.

I am using ImagePath property because my controller has about nine methods that output image. ImagePath property is defined as follows.


public string ImagePath
{
    get
    {
        var server = ControllerContext.HttpContext.Server;
        var imagePath = server.MapPath("~/images/bunny-peanuts.jpg");
        return imagePath;
    }
}

Image transformations

Right now WebImages provides us with the following image transformations:

  • cropping,
  • horizontal flip,
  • vertical flip,
  • resize,
  • rotate left,
  • rotate right,
  • text watermark,
  • image watermark.

All these transformations can be also found from my sample application.

Controller actions

Those of you who just want to see the code – here are all the controller actions that output image with some transform.


public void GetCropped()
{
    new WebImage(ImagePath)
        .Crop(50, 50, 50, 50) // crop 50px from all sides
        .Write();
}
public void GetHorizontalFlip()
{
    new WebImage(ImagePath)
        .FlipHorizontal()
        .Write();
}
public void GetVerticalFlip()
{
    new WebImage(ImagePath)
        .FlipVertical()
        .Write();
}
public void GetResized()
{
    new WebImage(ImagePath)
        .Resize(200, 200) // resize image to 200x200 px
        .Write();
} 
public void GetRotateLeft()
{
    new WebImage(ImagePath)
        .RotateLeft()
        .Write();
}
public void GetRotateRight()
{
    new WebImage(ImagePath)
        .RotateRight()
        .Write();
}
public void GetTextWatermark()
{
    new WebImage(ImagePath)
        .AddTextWatermark("Watermark", "white",14,"Bold")
        .Write();
} 
public void GetImageWatermark()
{
    var watermarkPath = HttpContext.Server.MapPath("~/images/watermark.png");
    var watermark = new WebImage(watermarkPath);
 
    new WebImage(ImagePath)
        .AddImageWatermark(watermark)
        .Write();
} 

As you can see all these methods are very simple and syntax is very short. By example, compare WebImage.Resize() to clean resize method given in my blog posting Resizing images without loss of quality. All other stuff in GDI+ is similar rocking on code. WebImage saves you from complex and hard to debug GDI+ code.

ChartResult: Testable ASP.NET MVC 3 controller actions that return Chart

Lately I blogged about charts support in ASP.NET MVC 3 beta. This posting showed how to get chart initialized and sent to client quickly. In this posting I will show you how to use Chart with ChartResult to make our chart operations testable.

Source

You can find source code of this posting from my Visual Studio experiments repository at GitHub.

Source code @ GitHub Source code repository
GitHub

Model

Let’s start with simple model that returns data for chart. In real life you will use database or other data source in model but I save your time and use simple model.


public class ChartModel
{
    public virtual IList GetChartData()
    {
        return new ArrayList
                   {
                   new { X = DateTime.Now.AddMonths(-2), Y = 200 },
                   new { X = DateTime.Now.AddMonths(-1), Y = 300 },
                   new { X = DateTime.Now, Y = 500 }
                   };
    }
}

Although this model is taken from my charts posting I have minor change here: GetChartData() method is virtual because otherwise Moq cannot mock it.

Controller

Here is the full code of controller. To make controller testable I created constructor that takes model as argument. Don’t forget that in the real-life scenario this model will communicate with some data store.


public class HomeController : Controller
{
    private readonly ChartModel _model;
 
    public HomeController(ChartModel model)
    {
        _model = model;
    }
 
    public ActionResult Index()
    {
        ViewModel.Message = "Welcome to ASP.NET MVC!";
 
        return View();
    }
 
    public ChartResult GetChart()
    {
        var data = _model.GetChartData();
 
        var chart = new Chart(400, 200, ChartTheme.Blue)
                    .AddTitle("Price enquiries")
                    .DataBindTable(data, "X");
 
        return new ChartResult(chart, "png");
    }
 
    public ActionResult About()
    {
        return View();
    }        
}

In my example application I use custom controller factory. If you want to see it, feel free to download the source code.

ChartResult

Here is my ChartResult class that does nothing more than outputs the chart.


public class ChartResult : ActionResult
{
    private readonly Chart _chart;
    private readonly string _format;
 
    public ChartResult(Chart chart, string format)
    {
        if (chart == null)
            throw new ArgumentNullException("chart");
 
        _chart = chart;
        _format = format;
 
        if (string.IsNullOrEmpty(_format))
            _format = "png";
    }
 
    public Chart Chart
    {
        get { return _chart; }
    }
 
    public string Format
    {
        get { return _format; }
    }
 
    public override void ExecuteResult(ControllerContext context)
    {
        _chart.Write(_format);
    }
}

I made also chart and format available as properties so you have better control over this action result in your tests.

Test

To test if GetChart() works like expected we will use the following primitive test. I am using nUnit and moq for tests. You can add them both to your test project using NuPack.


[TestFixture]
public class HomeControllerTests 
{
    [Test]
    public void GetChartReturnsChart()
    {
        var data = GetChartData();
        var mock = new Mock<ChartModel>();
        mock.Setup(c => c.GetChartData())
            .Returns(data);
 
        var controller = new HomeController(mock.Object);
        var result = controller.GetChart();
 
        mock.Verify();
        Assert.IsNotNull(result, "Result is null");
        Assert.IsInstanceOf<ChartResult>(result,"Result is not ChartResult");
    }
 
    private static IList GetChartData()
    {
        return new ArrayList
                    {
                    new { X = DateTime.Now.AddMonths(-2), Y = 200 },
                    new { X = DateTime.Now.AddMonths(-1), Y = 300 },
                    new { X = DateTime.Now, Y = 500 }
                    };
    }
}

Running the test gives us the following nice result.

GetChart() test results

So, seems like our controller works like expected.

Conclusion

Although new helper for charts is very powerful and works like charm we still need to write some code to keep our controller actions testable. ASP.NET MVC with its flexible architecture helps us out. All we had to do was to remove model instantiation out from controller and add ChartResult class to our project so we follow they way how ASP.NET MVC controllers work.

More Posts Next page »