Garry Pilkington


Application Developer
Liverpool, UK
Blog moved
I have decided to move my blog from here over to Don't Believe the Type. There are a number of reasons I have decided to do this mainly:-

  • I need more control over how the blog looks.
  • Too much spam and little control over how to manage it.
  • Bring the url in line with my new company name Asterope Systems
  • I want to focus on other technical aspects not just ASP.Net

I have loved being part of the asp.net blogging community here, but you will notice a lack of posts in the past year. This has been down to mainly being more mobile and not having the right tooling in place (use WinRT surface a lot of the time). Now that I am hosting on Wordpress, I have a better writing environment and have more general control over the site.

I have imported all these posts over and I am in the process of tidying them up to look nicer.

Hope you will join me over at my new blog.

Thanks
Garry Pilkington
Web Site Performance and Assembly Versioning – Part 3 Versioning Combined Files Using Mercurial

Minification and Concatination of JavaScript and CSS Files
Versioning Combined Files Using Subversion
Versioning Combined Files Using Mercurial – this post

I have worked on a project recently where there was a need to version the system (library dll, css and javascript files) by date and Mercurial revision number. This was in the format:-

0.12.524.407

{major}.{year}.{month}{date}.{mercurial revision}

Each time there is an internal build using the CI server, it would label the files using this format. When it came time to do a major release, it became v1.{year}.{month}{date}.{mercurial revision}, with each public release having a major version increment.

Also as a requirement, each assembly also had to have a new GUID on each build.

So like in previous posts, we need to edit the csproj file, and add a couple of Default targets.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <Project ToolsVersion="4.0" DefaultTargets="Hg-Revision;AssemblyInfo;Build" 
   3:     xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   4: <PropertyGroup>

Right below the closing tag of the entire project we add our two targets, the first is to get the Mercurial revision number. We first need to import the tasks for MSBuild which can be downloaded from http://msbuildhg.codeplex.com/

   1: <Import Project="..\Tools\MSBuild.Mercurial\MSBuild.Mercurial.Tasks" />
 
   1: <Target Name="Hg-Revision">
   2:  <HgVersion LocalPath="$(MSBuildProjectDirectory)" Timeout="5000" 
   3:     LibraryLocation="C:\TortoiseHg\">
   4:   <Output TaskParameter="Revision" PropertyName="Revision" />
   5:  </HgVersion>
   6:  <Message Text="Last revision from HG: $(Revision)" />
   7: </Target>
With the main Mercurial files being located at c:\TortoiseHg

To get a valid GUID we need to escape from the csproj markup and call some c# code which we put in a property group for later reference.

   1: <PropertyGroup>
   2:  <GuidGenFunction>
   3: <![CDATA[ 
   4: public static string ScriptMain() { 
   5: return System.Guid.NewGuid().ToString().ToUpper(); 
   6: } 
   7: ]]>
   8:  </GuidGenFunction>
   9: </PropertyGroup>

Now we add in our target for generating the GUID.

   1: <Target Name="AssemblyInfo">
   2:     <Script Language="C#" Code="$(GuidGenFunction)">
   3:       <Output TaskParameter="ReturnValue" PropertyName="NewGuid" />
   4:     </Script>
   5:     <Time Format="yy">
   6:       <Output TaskParameter="FormattedTime" PropertyName="year" />
   7:     </Time>
   8:     <Time Format="Mdd">
   9:       <Output TaskParameter="FormattedTime" PropertyName="daymonth" />
  10:     </Time>
  11:     <AssemblyInfo CodeLanguage="CS" OutputFile="Properties\AssemblyInfo.cs" 
  12:         AssemblyTitle="name" AssemblyDescription="description" 
  13:         AssemblyCompany="none" AssemblyProduct="product" 
  14:         AssemblyCopyright="Copyright ©" 
  15:         ComVisible="false" CLSCompliant="true" Guid="$(NewGuid)" 
  16:         AssemblyVersion="$(Major).$(year).$(daymonth).$(Revision)" 
  17:         AssemblyFileVersion="$(Major).$(year).$(daymonth).$(Revision)" />
  18:   </Target>

So this will give use an AssemblyInfo.cs file like this just prior to calling the Build task:-

   1: using System;
   2: using System.Reflection;
   3: using System.Runtime.CompilerServices;
   4: using System.Runtime.InteropServices;
   5:  
   6: [assembly: AssemblyTitle("name")]
   7: [assembly: AssemblyDescription("description")]
   8: [assembly: AssemblyCompany("none")]
   9: [assembly: AssemblyProduct("product")]
  10: [assembly: AssemblyCopyright("Copyright ©")]
  11: [assembly: ComVisible(false)]
  12: [assembly: CLSCompliant(true)]
  13: [assembly: Guid("9C2C130E-40EF-4A20-B7AC-A23BA4B5F2B7")]
  14: [assembly: AssemblyVersion("0.12.524.407")]
  15: [assembly: AssemblyFileVersion("0.12.524.407")]

Therefore giving us the correct version for the assembly. This can be referenced within your project whether web or Windows based like this:-

   1: public static string AppVersion()
   2:  {
   3:    return Assembly.GetExecutingAssembly().GetName().Version.ToString();
   4:  }

As mentioned in previous posts in this series, you can label css and javascript files using this version number and the GetAssemblyIdentity task from the main MSBuild task library build into the .Net framework.

   1: <GetAssemblyIdentity AssemblyFiles="bin\TheAssemblyFile.dll">
   2:  <Output TaskParameter="Assemblies" ItemName="MyAssemblyIdentities" />
   3: </GetAssemblyIdentity>

Then use this to write out the files:-

   1: <WriteLinestoFile 
   2:     File="Client\site-style-%(MyAssemblyIdentities.Version).combined.min.css" 
   3:     Lines="@(CSSLinesSite)" Overwrite="true" />
Web Site Performance and Assembly Versioning – Part 2 Versioning Combined Files Using Subversion

Ok so it took a while to post this second part. Many apologies, we had a big roll out of a new platform at work and many things had to get sidelined.

So this is the second part in a short series of website performance and using versioning to help improve it.

Minification and Concatination of JavaScript and CSS Files
Versioning Combined Files Using Subversion – this post
Versioning Combined Files Using Mercurial – published shortly

In the previous post we used AjaxMin to shrink js and css files then concatenated them into one file each which had the file name of site-script.combined.min.js and site-style.combined.min.css.

These file names are fine, but you can configure IIS 7 to cache these static files and so lower the amount of data transferred between server and client. This is done by editing the response headers in IIS.

1. In IIS7 Manager, choose the directory where these files are located and select HTTP Response Headers.

1

2. Check the Expire Web Content and set a time period well into the future.

2

3. When refreshing the web page, the server will respond with HTTP 304 forcing the browser to retrieve the file from its cache.

3

4. As can be seen in FireBug, the Cache-Control header has a max age of 31536000 seconds which equates to 365 days.

4

 

The server will always send this HTTP 304 message unless the file changes forcing it to send new content. To help force this we can change the file name based on the latest build using the SVN revision number in the filename. So we have lowered data transfer on content that hasn’t changed, but forced it to be sent when you have made a change to the css or js files.

Now to get the SVN revision number in to the file name.

1. Import the MSBuildCommunityTasks targets which can be dowloaded from here.

   1: <Import Project="$(MSBuildExtensionsPath)
   2: \MSBuildCommunityTasks
   3: \MSBuild.Community.Tasks.Targets" />

2. Edit the BeforeBuild target to call out to svn and get the latest revision

   1: <SvnVersion LocalPath="$(MSBuildProjectDirectory)" 
   2:     ToolPath="$(ProgramFiles)\VisualSVN Server\bin">
   3: <Output TaskParameter="Revision" PropertyName="Revision" />
   4: </SvnVersion>

3. Set it to update the project AssemblyInfo.cs file for the svn revision.

   1: <FileUpdate Files="Properties\AssemblyInfo.cs"
   2:     Regex="(\d+)\.(\d+)\.(\d+)\.(\d+)"
   3:     ReplacementText="$1.$2.$3.$(Revision)" />

4. Now edit the AfterBuild target to get the full dll version. You could combine these two steps and just get the version from svn, I am working on one project that updates the AssemblyInfo file and another project that allows manual editing of the file, but needs that version within the file name; so I just combined the two for this post.

   1: <MSBuild.ExtensionPack.Framework.Assembly 
   2:     TaskAction="GetInfo" 
   3:     NetAssembly="$(OutputPath)\mydll.dll">
   4: <Output TaskParameter="OutputItems" ItemName="Info" />
   5: </MSBuild.ExtensionPack.Framework.Assembly>
   6: <Message Text="Version: %(Info.AssemblyVersion)" 
   7:     Importance="High" />

5. Use this Info.AssemblyVersion to write out the combined css and js files as described in the last post.

   1: <WriteLinestoFile File="Scripts\site-%(Info.AssemblyVersion).combined.min.js" 
   2:     Lines="@(JSLinesSite)" Overwrite="true" />

 

In the next post I will cover doing the same, but for a Mercurial repository.

Posted: Apr 03 2012, 02:56 PM by capgpilk | with 1 comment(s)
Filed under: , , ,
Web Site Performance and Assembly Versioning

I originally wanted to write this post in one, but there is quite a large amount of information which can be broken down into different areas, so I am going to publish it in three posts.

Minification and Concatination of JavaScript and CSS Files – this post
Versioning Combined Files Using Subversion
Versioning Combined Files Using Mercurial – published shortly

Website Performance

There are many ways to improve web site performance, two areas are reducing the amount of data that is served up from the web server and reducing the number of files that are requested.

Here I will outline the process of minimizing and concatenating your javascript and css files automatically at build time of your visual studio web site/ application.

To edit the project file in Visual Studio, you need to first unload it by right clicking the project in Solution Explorer. I prefer to do this in a third party tool such as Notepad++ and save it there forcing VS to reload it each time I make a change as the whole process in Visual Studio can be a bit tedious.

Now you have the project file, you will notice that it is an MSBuild project file.

I am going to use a fantastic utility from Microsoft called Ajax Minifier. This tool minifies both javascript and css.

1. Import the tasks for AjaxMin choosing the location you installed to. I keep all third party utilities in a Tools directory within my solution structure and source control. This way I know I can get the entire solution from source control without worrying about what other tools I need to get the project to build locally.

AjaxMin

   1: <Import Project="..\Tools\MicrosoftAjaxMinifier\AjaxMin.tasks" />

2. Now create ItemGroups for all your js and css files like this. Separating out your non minified files and minified files. This can go in the AfterBuild container.

   1: <Target Name="AfterBuild">
   2:  
   3:     <!-- Javascript files that need minimizing -->
   4:     <ItemGroup>
   5:       <JSMin Include="Scripts\jqModal.js" />
   6:       <JSMin Include="Scripts\jquery.jcarousel.js" />
   7:       <JSMin Include="Scripts\shadowbox.js" />
   8:     </ItemGroup>
   9:     <!-- CSS files that need minimizing -->
  10:     <ItemGroup>
  11:       <CSSMin Include="Content\Site.css" />
  12:       <CSSMin Include="Content\themes\base\jquery-ui.css" />
  13:       <CSSMin Include="Content\shadowbox.css" />
  14:     </ItemGroup>

 

   1: <!-- Javascript files to combine -->
   2:     <ItemGroup>
   3:       <JSCat Include="Scripts\jqModal.min.js" />
   4:       <JSCat Include="Scripts\jquery.jcarousel.min.js" />
   5:       <JSCat Include="Scripts\shadowbox.min.js" />
   6:     </ItemGroup>
   7: <!-- CSS files to combine -->
   8:     <ItemGroup>
   9:       <CSSCat Include="Content\Site.min.css" />
  10:       <CSSCat Include="Content\themes\base\jquery-ui.min.css" />
  11:       <CSSCat Include="Content\shadowbox.min.css" />
  12:     </ItemGroup>

 

3. Call AjaxMin to do the crunching.

   1: <Message Text="Minimizing JS and CSS Files..." Importance="High" />
   2:     <AjaxMin JsSourceFiles="@(JSMin)" JsSourceExtensionPattern="\.js$" 
   3:     JsTargetExtension=".min.js" JsEvalTreatment="MakeImmediateSafe" 
   4:     CssSourceFiles="@(CSSMin)" CssSourceExtensionPattern="\.css$" 
   5:     CssTargetExtension=".min.css" />

This will create the *.min.css and *.min.js files in the same directory the original files were.

4. Now concatenate the minified files into one for javascript and another for css. Here we write out the files with a default file name. In later posts I will cover versioning these files the same as your project assembly again to help performance.

   1: <Message Text="Concat JS Files..." Importance="High" />
   2:     <ReadLinesFromFile File="%(JSCat.Identity)">
   3:       <Output TaskParameter="Lines" ItemName="JSLinesSite" />
   4:     </ReadLinesFromFile>
   5:     <WriteLinestoFile File="Scripts\site-script.combined.min.js" Lines="@(JSLinesSite)" 
   6:     Overwrite="true" />
   7:     <Message Text="Concat CSS Files..." Importance="High" />
   8:     <ReadLinesFromFile File="%(CSSCat.Identity)">
   9:       <Output TaskParameter="Lines" ItemName="CSSLinesSite" />
  10:     </ReadLinesFromFile>
  11:     <WriteLinestoFile File="Content\site-style.combined.min.css" Lines="@(CSSLinesSite)" 
  12:     Overwrite="true" />

5. Save the project file, if you have Visual Studio open it will ask you to reload the project. You can now run a build and these minified and combined files will be created automatically.

6. Finally reference these minified combined files in your web page.

In the next two posts I will cover versioning these files to match your assembly.

Full Circle

Things have been a little bit hectic these past 6 months hence the lack of posts. My excuse is a good one though, my wife gave birth to our first son Tom back in September and it has been one hell of a rollercoaster ride since then. Things have settled back down now thank hevens.

My last development gig didn't quite work out so now I have took the plunge and started contracting. It turns out my first contract is with the NHS trust that I started my development career with, which seems a bit wierd as that was 10 years ago. A lot has changed in the techniques and tools the NHS now use to develop with, there is a lot more .net with a slant towards the web side of the spectrum (at least in this NHS trust). They are really getting to grips with the MVC platform, so you will hopefully see some MVC posts coming up.

The really suprising thing is that the Intranet I developed back in 2001 (classic asp migrated to .net 1.0) is still up and running and will finally be fazed out these coming weeks (to Sharepoint). It is like seeing an old friend all grown up.

 

Branching and Merging with TortoiseSVN

For this example I am using Visual Studio 2010, TortoiseSVN 1.6.6, Subversion 1.6.6 and AnkhSVN 2.1.7819.411, so if you are using different versions, some of these screen shots may differ.

This is assuming you have your code checked in to the trunk directory and have a standard SVN structure of trunk, branches and tags. There are a number of developers who prefer to develop solely in a branch and never touch the trunk, but the process is generally the same and you may be on a small team and prefer to work in the trunk and branch occasionally.

There are three steps to successful branching. First you branch, then when you are ready you need to reintegrate any changes that other developers may have made to the trunk in to your branch. Then finally when your branch and the trunk are in sync, you merge it back in to the trunk.

Branch

  1. Right click project root in Windows Explorer > TortoiseSVN > Branch/Tag
    1 - 1

  2. Enter the branch label in the ‘To URL’ box. For example /branches/1.1
    1 - 2

  3. Choose Head revision
  4. Check Switch working copy
  5. Click OK
  6. Make any changes to branch
    1 - 3

  7. Make any changes to trunk
    1 - 4

  8. Commit any changes
    1 - 5

For this example I copied the project to another location prior to branching and made changes to that using Notepad++. Then committed it to SVN, as this directory is mapped to the trunk, that is what gets updated.

 

Merge Trunk with Branch

  1. Right click project root in Windows Explorer > TortoiseSVN > Merge
    2 - 1

  2. Choose ‘Merge a range of revisions’
    2 - 2

  3. In ‘URL to merge from’ choose your trunk
    2 - 3

  4. Click Next, then the ‘test merge’ button. This will highlight any conflicts. Here we have one conflict we will need to resolve because we made a change and checked in to trunk earlier
    2 - 4


    2 - 5
  5. Click merge. Now we have the opportunity to edit that conflict
    2 -5 - a

  6. This will open up TortoiseMerge which will allow us to resolve the issue. In this case I want both changes.
    2 -5 - b


    2 -5 - c


    2 -5 - d

  7. Perform an Update then Commit
    2 - 7 - a


    2 - 7 - b

  8. Reloading in Visual Studio shows we have all changes that have been made to both trunk and branch.2 - 8

Merge Branch with Trunk

  1. Switch working copy by right clicking project root in Windows Explorer > TortoiseSVN > switch3 - 3

  2. Switch to the trunk then ok
    3 - 4

  3. Right click project root in Windows Explorer > TortoiseSVN > merge
    3 - 5

  4. Choose ‘Reintegrate a branch’
    3 - 6

  5. In ‘From URL’ choose your branch then next
    3 - 7

  6. Click ‘Test merge’, this shouldn’t show any conflicts
    3 - 8

  7. Click Merge
  8. Perform Update then Commit
    3 - 10


    3 - 10 - a

  9. Open project in Visual Studio, we now have all changes.

So there we have it we are connected back to the trunk and have all the updates merged.

Setting Up MVC Using StructureMap, Moq and NUnit...Quickly

When I was first attracted to the Microsoft MVC Framework, one of my main ambitions was to develop using a more test driven approach. There are ways to include Unit testing with WebForms, but the friction was just too much to justify on the web projects I was involved with.

As soon as I started using MVC I was amazed at how easy it was to incorporate unit testing and isolation frameworks; in a way it became more of a natural process.

Here in this post I am quickly covering getting up and running with unit testing, isolation frameworks and MVC.

My tools of choice are:-

This example is a simple green field site; the typical File >> New Project >> MVC application.

So we have our site, I want data from a database (in this example I won’t be bothering with creating a data store, which shows just how handy stubs can be).

I want to run a test on the data and send it off to the view, simple stuff.

In Models, I want to create a data repository, but I don’t want to code against a concrete type, I will use an interface.


public interface IRepository
{
    int GetTotalOrders();
}
 
public class Repository : IRepository
{
    public int GetTotalOrders()
    {
        return 55;
    }
}

Here I have a simple method which in this case returns a hard coded integer.

So far so good, the site compiles.

I want the controller to handle this method call via an Order class like this.


public class Order
{
    private IRepository Repository;
 
    public Order(IRepository repository)
    {
        Repository = repository;
    }
 
    public int GetTotalOrders()
    {
        return Repository.GetTotalOrders();
    }
}

As can be seen there are two SOLID principles in use here. The Order is dependent on the Repository class, but this dependency is injected in to the constructor. Also it is handed an interface and not a concrete type.

So my controller can call the GetTotalOrders method on the Order and let that handle the repository, but before all that I want a test in place that will make sure I am returning that data from the repository.

Of course in the real world I don’t want to touch the database, and in this case I don’t even have one. Here is the unit test that stubs out the repository call.


[Test]
public void GetTotalOrders_returns_56()
{
    //Arrange
    var repositoryMock = new Mock<IRepository>();
    repositoryMock.Setup(r => r.GetTotalOrders()).Returns(56);
 
    Order orders = new Order(repositoryMock.Object);
 
    //Act
    int expectedValue = 56;
    int actualValue = orders.GetTotalOrders();
 
    //Assert
    Assert.AreEqual(expectedValue, actualValue);
}

In this case I am forcing the repository to return an integer of 56, not the 55 from the concrete class. The solution compiles and the test passes.

mvc_post_1

Great, but how do we code this for the controller.


public class HomeController : Controller
{
    public HomeController()
    {
    }
 
    public ActionResult Index()
    {
        Repository repository = new Repository();
 
        Order orders = new Order(repository);
 
        int totalOrders = orders.GetTotalOrders();
 
        ViewData["TotalOrders"] = totalOrders.ToString();
 
        return View();
    }
}

This works fine, but I don’t want the Index method to be responsible of creating the Repository object, so we take that out and let the constructor handle that.


public class HomeController : Controller
{
    private readonly IRepository Repository;
 
    public HomeController(IRepository repository)
    {
        Repository = repository;
    }
 
    public ActionResult Index()
    {
        Order orders = new Order(Repository);
 
        int totalOrders = orders.GetTotalOrders();
 
        ViewData["TotalOrders"] = totalOrders.ToString();
 
        return View();
    }
}

Now it compiles ok, the tests run ok, but the web application fails.


mvc_post_2

This is where we need to start injecting the dependencies needed. We need both an ApplicationRegistry and Bootstrapper class.


public class ApplicationRegistry : Registry
    {
        public ApplicationRegistry()
        {
            ForRequestedType<IRepository>()
             .TheDefault.Is.OfConcreteType<Repository>();
        }
    }

 

public static class Bootstrapper
{
    public static void ConfigureStructureMap()
    {
        ObjectFactory.Initialize
            (x => x.AddRegistry(new ApplicationRegistry()));
    }
}

The ApplicationRegistry class reads very fluently and simply injects any occurrence of the IRepository type with the Repository concrete type.

Next we need a controller factory which inherits from the MVC DefaultControllerFactory and is called from the Application_Start in the Global.asax file.


public class StructureMapControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(Type controllerType)
    {
        if (controllerType == null) return null;
 
        try
        {
            return ObjectFactory.GetInstance(controllerType) as Controller;
        }
 
        catch (StructureMapException)
        {
            System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());
 
            throw;
        }
    }
}


protected void Application_Start()
{
    Bootstrapper.ConfigureStructureMap();
    ControllerBuilder.Current.SetControllerFactory
      (new StructureMapControllerFactory());
 
    RegisterRoutes(RouteTable.Routes);
}

Now rebuilding and running the site we successfully retrieve the value from the repository.

WinMerge as a Comparison Tool in Visual Studio 2008

Ok I know VS 2010 is the new toy to be seen playing around with, but as I have just recently  got delivery of my new Windows 7 pc I thought I would document how to get WinMerge to work as a comparison tool with VS2008 Team System. If for anything, so I know myself when the time comes to do it all over again.

Team Foundation Server does have a built in comparison and merge tool, but personally I find WinMerge to be far better. Oh and it is free.

  1. After downloading and installing, you need to configure Visual Studio. Go to Tools >> Options

  2. Find the ‘Source Control’ section in the tree view and select ‘Visual Studio Team Foundation Server’

  3. Click the ‘Configure User Tools’ button.

    WinMerge1
  4. Click on the ‘Add’ button on the ‘Configure User Tools’ window.

  5. Enter these values in the textboxes:

    Extension: *
    Operation: Compare
    Command: C:\Program Files\WinMerge\WinMergeU.exe (or wherever you have installed WinMerge to)
    Arguments: /x /e /ub /wl /dl %6 /dr %7 %1 %2

    WinMerge2
  6. Click OK all the way back down to get back to the main IDE.

Now when you view a file history from Solution Explorer it will start up WinMerge.

Windows Explorer and Microsoft SkyDrive

Bit by bit more of our lives are moving in to the cloud. I have been a bit late to this party as I have never published my photos to Flikr or any other image sharing site. That is mainly because I want to keep them secret and I am really just after an off site backup solution. What I have been after is great easy storage with enough disk space for all my photographs. There are plenty of places out on the web which offer this service I know, but I want it cheap or free. This is where Microsoft SkyDrive comes in with a whopping 25GB of private storage.

Great, but what I was after was simple integration with the Windows UI without having to go through a web interface. This had deterred me from using it until I came across a piece of software called Cloud Desktop from Gladinet. After installation and a bit of minor configuration, it gives you access to your SkyDrive through a virtual network drive. It comes in three editions, with the Starter being free. The main limit of the free version is that you can only upload a maximum of 1000 files at a time. Simply drag and drop your files in to the virtual drive and you are away. A great resource to help you get up and running is this link from newbTech.

For easy synchronization between Windows directories and the cloud, there is always Live Mesh, but it would be great if Microsoft would release a SkyDrive API so we could have more control through our applications, perhaps hooking up the Sync Framework.

Multiple Strongly Typed Partial Views in MVC

Creating strongly typed views with the ASP.Net MVC framework is really easy, but what if you want to have multiple types on the same view? One way to achieve this is to create partial views for each type and creating a combined view model. Then the view will inherit this combined view model and each partial view will inherit from its component types.

In the following simple example I have a view which itself displays two partial views. This view inherits from a type I have called CombinedViewModel.

The hosting view

   <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
   Inherits="System.Web.Mvc.ViewPage<CombinedViewModel>" %>
   ...
    
   
   <asp:Content ID="Content1" ContentPlaceHolderID="MainContent"
   runat="server">
        
   <% Html.RenderPartial("PartialView1", ViewData.Model.Header); %>
   <% Html.RenderPartial("PartialView2", ViewData.Model.Detail); %>
    
  </asp:Content>

 

The controller passes the types in to the CombinedViewModel.

public ActionResult Detail(int id)
 {
  Header header = DataRepository.GetHeader(id);
  List<Detail> detail = DataRepository.GetDetail(id);
 
  CombinedViewModel viewData = new CombinedViewModel(header, detail);
 
  return View(viewData);         
 }

The CombinedViewModel

public class CombinedViewModel
{
 public Header  Header { get; private set; }
 public IEnumerable<Detail> Detail { get; private set; }  
 
public JobDetailViewModel(Header header, IEnumerable<Detail> detail)
{
 Header = header;
 Detail= detail;
}
}

 

So now each of the partial views can access the types they need.

The PartialViews

<%@ Control Language="C#"

Inherits="System.Web.Mvc.ViewUserControl<TestApp.Models.Header>" %>

<%= Model.CustomerTitle%>

<%@ Control Language="C#"

Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<TestApp.Models.Detail>>" %>

<%= Model.OrderNumber%>
Posted: Oct 20 2009, 09:29 AM by capgpilk | with 10 comment(s)
Filed under: , , ,
More Posts Next page »