Archives

Archives / 2008 / April
  • Why can't I be satisfied when I'm looking back on old applications?

    Most of the time I build an application I  have the feeling "this is going to be a great app. Good design, nice written code and a perfect application". I think most of you had the same feeling sometimes. But when I look back on previous applications, I say "What!? NO!!! This is not good, well this could have been done much better ... omg! What have I done! .. what a bad method name....". I don't know why I often feel like that when looking back on my previous apps. When I'm looking back on my code, I always find something I could have done better. Why can't I just write the perfect app, so I can go back later and say to my self "Well Fredrik, this one is great, good work!".

    Read more...

  • The configurable application, no need for recompilation and new deployment!

    The following I will write about is something I have used in some projects to see if it gives me any value, I haven't seen any evolutionary results yet, but maybe it's because I often move along to other projects when the previous one is completed ;)

    Let assume I have a User and the User has a property called Rebate. This method can have some business logic to calculate the rebate the use has when ordering products. Here is an dummy example of the method:

    class User { public double Rebate { get { return superUser ? 10: 5; } } }

     

    User user = new User(....);
    double rebate = user.Rebate;

     
    The business rule for calculating the Rebate is something that can be changed in the future based in new business needs. Can we do the changes without  a new recompilation and deployment of the application?

    By using the Interfaces and also the Factory Pattern we could solve this. Here is an example where an Interface is added to the User and a Factory is used to create the User:
     

    public interface IUser { double Rebate { get; } } class User : IUser { public double Rebate { get { return superUser ? 10: 5; } } }

     

    IUser user = UserFactory.Create(...);
    double rebate = user.Rebate;


    The UserFactory will now create an User an return an IUser. Because the factory creates the user I don't use "new User". I can now use late binding and load the assembly which has the implementation of the User and return it. I can for example use a configuration file where I specify the type of the user I want use.


    <object name="IUser" type="MyNamespace.User, MyAssembly, Version 1.0 ...">


    The UserFactory can now load the type specified in the configuration file and create an instance of it. If I need an new version of the User because
    some changes need to made based on business needs, I can create a new assembly and a new IUser. I can then modify my configuration file to make sure  the UserFactory loads my new implementation. By using this solution I don't need to compile my application when changes to classes is needed. Instead I create a new version of the class, put it into a new version of the assembly and deploy it. Then I only change the configuration file so the Factory gets my new implementation instead of the old version.


    class User : IUser
    {
        public double Rebate
        {
            get { return IsMegaUser() ? 11: 6; }
        }
    }


    <object name="IUser" type="MyNamespace.User, MyAssembly, Version 2.0 ...">

    Another solution to solve this could be to use Dependency Injection, where I inject a object with the implementation of the business logic. I can then for example use Spring.Net to inject the business object into my User. By using Spring.Net I can in a configuration file specify which business object that should be injected to the User class when it's instantiated. This will make it possible to only implement a new version of the business object rather then a new version of the User. I will not use this solution because it can be kind of ugly. But by using Spring.Net I can hide the injection of the dependency and never see it in my code. Let's think like an Object, would you like someone to easy change your behavior and you can't do any thing about it?

    I sometimes uses Interfaces and in some cases Factories, but not so often (It depends on the project and if the Customer already have specified a design to use). I use interfaces and factories when I want my application to be plugable, for example make it easy to inject Repositories into my Services etc, and also to make it possible to use Mock object during test etc.

    About using this solution for most of the classes in a application, wouldn't it in an Agile project sort of violate YAGNI!?

    It can sort of help the people that need to maintain the application after it's deployed, as long as the interface of the classes can be intact. What do you think about it? Is this something you use today in your application and have it result into something good?

    Read more...

  • Can the use of Extension methods break the Law of Demeter?

    To make an easy description of Law of Demeter we can summarize it to the following sentence:

    “In particular, an object should avoid invoking methods of a member object returned by another method.”

    What does this has to do with Extension methods? It depends on how it’s used. For example we have several Extension Methods for the IEnumerable interface, like Where and OrderBy. By using those methods we can easy select data out from lists, for example (I’m so worthless when it comes to give methods good name, and the following method is so stupid, but it’s only an example.):

    Read more...

  • ASP.Net MVC Framework - How do I design my apps with the MVC pattern and +P

    When I'm playing around with the ASP.NET MVC Framework I have created several prototype applications with different solutions to solve some "problems." In this post I will write down how I combine a Presentation Model (When I talk about Presentation Model in this post, I refer to a model which purpose is only to define a model for presentation purpose) with the MVC, it's what the P in MVC+P stands for. 

    When I build apps today I use Domain Driven Design and I use the MVC pattern in some of my web based applications. As many of you know the M in MVC stands for the Model and contains our entities, business logic can data access components. Often when I build my apps with the ASP.Net MVC Framework (still only use in as a prototype because the framework is under development) I create my own custom Controller Factory to support Dependency Injection (DI). For example I use constructor injection or setter injection to inject my Repositories or manual injection of Mock objects during test. I use Spring.Net as my DI framework because it’s the framework I like the most.

    Here is a simple example how my Controllers can look like and are prepared for constructor injection:


    public class HomeController : Controller { ICompanyRepository _companyRepository; public HomeController() : this(new CompanyRepository()) { } public HomeController(ICompanyRepository companyRepository) { this._companyRepository = companyRepository; } public ActionResult Index() { CompanyInfo companyInfo = this._companyRepository.GetCompanyInfo(); return RenderView("Index", companyInfo); } }

    As you can see I create an instance of a CompanyRepository in the default constructor, the reason to this is because if I create a normal instance of the HomeController, I want it to use a default Repository. I also have a constructor which takes a ICompanyRepository as an argument, this is because to enable constructor injection. I can use the constructor to pass in my Mock object of the CompanyRepository, or I can use Spring.Net to inject a ICompanyRepository, which I use in my own custom Controller Factory. Here is how my test could look like where I have a Mock object for the CompanyRepository:

        MockCompanyRepository mockCompanyRepository = new MockCompanyRepository();
    
        mockCompanyRepository.Create(new CompanyInfo("........"));
    
        CompanyController companyController = new CompanyController(mockCompanyRepository);
    
        var result = CompanyController.Index() as RenderViewResult;
    
        //Assert...
    


    Note: If you have read my Step by Step Guide, I use the LINQ to SQL's DataContext object directly in my Controllers, it's because they can sometimes serve as a "Repository" because the power of the LINQ.

    When I use MasterPage which should always render a part of my Model, like content for a Menu etc, or when I need to render more than one entities of my Model, I need to make sure my Controllers will fill the ViewData property with more information than just one single entity from my Model. In this case I may have several Repositories which I need to call from my Controllers. If I use constructor injection, I need to add an argument to a Controller's constructor for each Repository. This can make the constructor cumbersome. To solve the issue and reduce the number of argument, I instead use setter injection, so I inject the Repositories needed through a set method (using properties). By doing this I can easy manually inject my Mock objects in my test:

        MockCompanyRepository mockCompanyRepository = new MockCompanyRepository();
        MockCustomerRepository mockCustomerRepository = new MockCustomerRepository();
    
        //...
    
        CompanyController companyController = new CompanyController();
    
        companyController.CompanyRepository = mockCompanyRepository;
        companyController.CustomerRepository = mockCustomerRepository;
    
        var result = CompanyController.Index() as RenderViewResult;
    
        //Assert...
    

    I can still reuse my own custom Controller Factory without changes to support setter injection, because I simple only let Spring.Net know that I want to inject my Repositories by using setter injection. When I use setter injection, I don't create an instance of the default Repository or Repositories in the default constructor of the Controller.

    The following is an example of a Controller which uses to Repositories and pass two entities to the "View":

    public class HomeController : Controller
    {
        ICompanyRepository _companyRepository;
        ICustomerRepository _customerRepository;
    
        public HomeController() { }
    
    
        public ActionResult Index()
        {
            ViewData["CompanyInfo"] = this.CompanyRepository.GetCompanyInfo();
    ViewData["Customer"] = this.CustomerRepository.GetCustomer(); return RenderView(); } public ICustomerRepository CustomerRepository { get { if (this._customerRepository == null) this._customerRepository = new CustomerRepository(); return this._customerRepository; } set { this._customerRepository = value; } } public ICompanyRepository CompanyRepository { get { if (this._companyRepository == null) this._companyRepository = new CompanyRepository(); return this._companyRepository; } set { this._companyRepository = value; } } }

    The Index method will now return two entities. Assume the CompanyInfo is for the MasterPage and the Customer for the Content Page. The ViewData property in this case will sort of be a Presentation Model ("The essence of a Presentation Model is of a fully self-contained class that represents all the data and behavior of the UI window") but don't contain any behavior.

    Something that can make the above Controller or other Controllers ugly and start to smell, is when most action method must set the ViewData for the Model which the MasterPage will render. There is a tiny little problem regarding to how I will work and think when it comes to Test Driven Developement, when I use a MasterPage or User Controls on a View which will render different models. The problem is, when I create a test for a Controller before the Controller is implemented, I must know about what Models the UI will render, all entity objects even for the MasterPage and User Controls.  I can't only assume that the CustomerController's List action method will return a list of Customers, I also need to have in mind the model the MasterPage and User Controls will use and when writing the test. Well basically I can ignore it, but it can affect how my ViewData will look like, and what key I need to use to get access to my list of Customers etc. This is something that I don't want to care about for every action method I want to create a test for. I also like the way I can type the ViewData property for the View. To solve the issue I decided to create a base class called PresentationModel. This class have one typed property for the model the MasterPage should render, MasterPageModel and one for the Repository which will get the Model for the MastePage, here is an example:

    public class PresentationModel
    {
        private CompanyInfo _companyInfo;
    
        public CompanyInfo MasterPageModel
        {
            get
            {
                if (this.CompanyRepository == null)
                    throw new ApplicationException("A ICompanyRepository must be set");
    
                if (this._companInfo == null)
    this._companyInfo = this.CompanyRepository.GetCompanyInfo(); return this._companyInfo; } set { this._companyInfo = value; } } public ICompanyRepository CompanyRepository { get; set; } }


    If the Model or the MasterPage is changed and that affect what the MastePage should render, I only need to change what model the PresentationModel class returns through the MastePageModel property, I don't need to go through all action methods and update them. That is one benefit with this design solution.

    Note: I use a property for the CompanyRepository to make it easy to add a Mock object in my tests.

    The PresentationModel is the type I specify for the MastePage to make it typed.

    public partial class Site : System.Web.Mvc.ViewMasterPage<PresentationModel>
    {
    }


    I then create a sub class of the PresentationModel called GenericPresentationModel. The GenericPresentaionModel class is a generic class which inherits from the PresentationModel and have a generic property called Model.

    public class GenericPresentationModel<T> : PresentationModel
    {
        public GenericPresentationModel() {}
    
        public GenericPresentationModel(T model)
        {
            this.Model = model;
        }
    
        public T Model { get; set; }
    }


    The Controllers can now use the GenericPresentationModel and pass it to the View, the following Controller has an Action method which will render a Customer:


    public
    ActionResult Index() { Customer customer = this.CustomerRepository.GetCustomer(); var presentationModel = new GenericPresentationModel<Customer>(customer); return RenderView("Index", presentationModel); }


    Because I pass the GenericPresentationModel to my View, I can also type the View:

    public partial class CustomerView : ViewPage<GenericresentationModel<Customer>>
    {
    }

    Then my ViewData property of my View will be of Type GenericPresentationModel<Customer>. So I can easy get access to my Customer by using ViewData.Model.

    The following example shows how the test of an Action which will render a Customer could look like:


    MockCustomerRepository mockCustomerRepository = new MockCustomerRepository(); //... HomeController controller = new HomeController(); controller.CustomerRepository = mockCustomerRepository(); var result = controller.Index() as RenderViewResult; var presentationModel = result.ViewData as GenericPresentationModel<Customer>; //Assert.....


    Because I don't use the MastePageModel property in my test of the Index method, I don't need to inject the Mock Repository for the PresentationModel base class. When I created the PresentationModel I have already created a test to make sure the PresentationModel returns the correct data, so I don't need to care about testing that again in my other tests.

    I still use this approach in a prototype solution to see how well it will work. When I work with Domain Driven Design I often need to render different information from different entities from my domain model. In my case I don't always want to pass several entities to my Views, so instead I create new object that will combine information from different entities, with another word, I create a Presentation Model. Most larger apps which I have created with the ASP.Net MVC Framework, often result in the use of a Presentation Model, and that is the P in the MVC+P. I know that several people don't like this because it requires us to create a lot of extra classes, but the benefits is that the Views will use the Presentation Model and don't even need to know about the domain model. If we don't pass a single entity from our domain model to the View, instead we use a Presentation Model and map the domain model to the Presentation Model, we can change the domain model, and it doesn't need to change the Views, only the mapping between the Presentation Model and the domain model. To be honest I don't create a complete Presentation Model, I still pass entities from the domain model to the View, mostly to keep it simple and not spend extra time to write new classes for each View.

    I'm interested about what you think, how you solve similar problems, do you use similar solutions that I do and have notice problems that I haven't notice yet, please let me know.

    Read more...

  • ASP.Net MVC Framework pre- Preview 3 - A Step by Step guide to create a simple web app.

    Yesterday I posted a step by step guide by using the Preview 2 of the ASP.Net MVC Framework, the following is an updated version that targets the pre-release of the Preview 3 version of the ASP.Net MVC Framework.

    In this post you will learn how to use most of the new features in the pre-release of the Preview 3 version of the ASP.NET Framework, you will also get a basic understanding about how to use LINQ to SQL. This step by step guide shouldn't be used as a "best way to create and design" a web applications by using the ASP.NET MVC Framework, this guide should only be used to get started with the MVC Framework in a fast and easy way and learn different ways to use some of the features shipped with the ASP.Net MVC Framework pre-release Preview 3.

    To get the pre-release version, you can download it from here.

    In this step by step guide you are going to create a web based application where you will be able to list and modify customers. This step by step guide will use C# 3.0 and the Northwind database.


    1. Open Visual Studio 2008


    2. Create a new Project and select the ”ASP.NET MVC Web Project” project from the "My Template" section and name it to “CustomerApp”.


    3. Open global.asax and walk through the code. In Global.asax you can specify your routes. In this step by step guide you will use the default settings.

    routes.MapRoute(
                   "Default",                                              // Route name
                   "{controller}/{action}/{id}",                           // URL with parameters
                   new { controller = "Home", action = "Index", id = "" }, // Parameter defaults
                   new { controller = @"[^\.]*" }                          // Parameter constraints
               );


    As you can see, there is a new method added to the RouteCollection, MapRoute. This method can be used to make the configuration of routing more cleaner. You can still use the old way with the Route object.

    The first thing to do is to create your business objects (your Model) which your Controllers will interact with. In this step by step guide you will use LINQ to SQL, even if it’s not advisable to generate domain models out from a data source you will learn how to do it, only to get up and running fast.

    Note: The business objects belongs to the Model in the MVC pattern.


    4. Right click on the Models folder in the Solution Explorer and select Add > New Item.

    Select the “LINQ to SQL Classes” template and name the file to “Northwind.dbml” and press the Add button.

    To create your Model out from a data source you need to add a database connection to Visual Studio. This can be done by using the Server Explorer. In the Solution Explorer, right click on the Data Connections node and select Add Connection. Enter the following information to connect to the Northwind database:

    Server Name: (local)

    Select the Northwind database, test the connection and press OK if you were able to connect to the database.

    A connection to the Northwind database will now be added under the “Data Connections” node in the Server Explorer. Expand the database and the Tables nodes; drag out the Customer table into the design view of the Northwind.dbml file. Save the file. When you save the file, LINQ to SQL will generate a Customer object for you where the columns from the Customers table will be added as properties to the Customer object. LINQ to SQL will also generate a DataContext object (NorthwindDataContext) which you will use later to access your information from the data source. Expand the Northwind.dbml file in the Solution Explorer, double click on the Northwind.designer.cs file and walk through the code. LINQ to SQL uses attributes to map classes to a table.

    Now it’s time to create the Controller which you are going to use in this application.


    5. Right click on the Controllers folder in the Solution Explorer and add a new item and select the “MVC Controller Class” template from the "My Templates" section, name it to “CustomerController”.


    6. Add a private field of the type NorhwindDataContext to the Controller and name the field to “northwindDataContext”. Set the field to an instance of the NorthwindDataContext object.

    Note: The NorthwindDataContext class will exist in the CustomerApp.Models namespace.


    using
    CustomerApp.Models; namespace CustomerApp.Controllers { public class CustomerController : Controller, IDisposable { private NorthwindDataContext northwindDataContext = new NorthwindDataContext(); //... } }


    7. Make sure the CustomerController implements the IDisposable interface, and implement the Dispose method and make sure it will make a call to the northwindDataContext’s Dispose method. This will make sure the NorthwindDataContext’s Dispose method will be called when the Controller have been used.


    public class
    CustomerController : Controller, IDisposable { private NorthwindDataContext northwindDataContext = new NorthwindDataContext(); //... public void Dispose() { this.northwindDataContext.Dispose(); } }


    8. Add an Action method and name it to “List”. The List action will retrieve all Customers from the Customers table of the Northwind database. LINQ to SQL will be used to get all the Customers, order the Customers by CompanyName. When all customers are retrieved make sure to render a View with the name “Customers” (The View will be added later to the project), the View should render a generic list of Customer objects.


    public
    ActionResult List() { List<Customer> customers = (from customer in northwindDataContext.Customers orderby customer.CompanyName select customer).ToList(); return RenderView("Customers", customers); }


    There are some changes to the Action methods between the Preview 2 and pre-release of Preview 3 of the ASP.Net MVC Framework. An Action method now returns a ActionResult. The RenderView method will now return a RenderViewResult, which inherits the ActionResult class. The changes are made to make it easier to create unit test without needing to create a lot of Mock objects, and also to make it easier in the future to support async. programming etc. You can read more about it on Scott Guthire's blog.

    Note: By default if we make a call to RenderView, without passing the name of the View, it will use the name of the Action method as the View to render.

    The following example shows an example of how a unit test can look like to test the List action method:


    [TestClass] public class CusomerControllerTest { [TestMethod] public void ListCustomerTest() { CustomerController custController = new CustomerController(); var result = custController.List() as RenderViewResult; Assert.IsNotNull(result, "Expected a RenderViewResult"); var customers = result.ViewData as List<Customer>; Assert.IsNotNull(result.ViewName, "Customers", "..."); Assert.IsNotNull(customers, "..."); //... } }


    Note: There is a helper method of the Controller base class called Redirect, which can be used to do a redirect within a Action method. The Redirect method returns a HttpRedirectResult, which inherits from the ActionResult class. The RedirectToAction method now returns an ActionRedirectResult class.


    9. Create a View with the name “Customers” which will render the generic list of Customer objects. To add a View, right click on the Views folder and add a new folder with the name “Customer”. Right click on the Customer folder and add a new item, select the “MVC View Page” template from the "My Template" section and name the View to “Customers”. Make sure the View data inherits from ViewPage<List<CustomerApp.Models.Customer>>. This will make sure the Model which is passed as an argument to the RenderView method is a known and typed for the View. Open the file Customers.aspx.cs file, replace so the page inherits from ViewPage<List<CustomerApp.Models.Customer>> instead of ViewPage.


    public partial class
    Customers : ViewPage<List<CustomerApp.Models.Customer>> { }


    10. Add code to render a list of Customers to the View, make sure the CustomerID and ContactName are listed. Open the Customer.aspx file, add an inline-code block and use foreach to iterate through the Customers, use the ViewData property to get access to the generic list of Customer objects.


    <%
    @ Page Language="C#" AutoEventWireup="true" CodeBehind="Customers.aspx.cs" Inherits="CustomerApp.Views.Customer.Customers" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title></title> </head> <body> <div> <table> <% foreach ( var customer in ViewData) { %> <tr> <td><%=Html.Encode(customer.CustomerID) %></td> <td><%=Html.Encode(customer.ContactName) %></td> </tr> <% } %> </table> </div> </body> </html>


    Make sure you have saved all files, compile and run the application. To the end of the URL add “Customer/List” and press enter. The URL will look something like this: http://localhost:<port number>/Customer/List.

    Your application will now make sure the Controller “CustomerController” will be used and also the Action method “List” will be invoked. If everything works, you will now see a list of CustomerID and ContactName.

    Note: The route that was defined in global.asax looks like this:


    {controller}/{action}/{id}


    When you enter a URL like “Customer/List”, the Customer will be the name of the Controller to be used, and the List the name of the Action method to be executed, the id in the route will be empty and will be ignored.


    11. Add a new Action method to the CustomerController and name it to “View”. The View method should have one argument with the name ID and the type of String. Make sure the method will use LINQ to SQL to get a Customer from the Customers table which matches the CustomerID passed as an argument. If a customer is not found, use the Redirect method and navigate to "/Errors/CustomerNotFound/<customer ID>". Make sure to render a View with the name “Customer”. The View should render a detail view of a Customer.

    public ActionResult View(string ID)
    {
        Customer customer = (from c in northwindDataContext.Customers
                             where c.CustomerID == ID
                             select c).FirstOrDefault();
    
        if (customer == null)
            return Redirect("/Error/CustomerNotFound/" + ID);
    
        return RenderView("Customer", customer);
    }

    Note: You will not implement a Controller or Views that will handle the error in this guide, it is used to demonstrate the Redirect method, and also how you can create a unit test that can check that the Action do the right thing when a CustomerID is passed to the Action method, and the customer can't be found.

    The following example will show you for example how you can write a test that will check if the user can't be found and that the Action method will do a Redirect:


    [TestMethod] public void ViewCustomerTest_Cant_Found_Customer() { CustomerController custController = new CustomerController(); var result = custController.View("Unknow Id") as HttpRedirectResult; Assert.IsNotNull(result, "Expected a http redirect"); //... }

    Because the Redirect method returns a HttpRedirectResult, you can in your Unit test, see if the Action method will do a Redirect or not.


    12. Add a new View to the Views/Customer folder and name it “Customer”. Make sure the Customer View will inherit form the ViewPage<CustomerApp.Models.Customer> class.


    public partial class
    Customer : ViewPage<CustomerApp.Models.Customer> { }


    13. Open the Customer.aspx page and add inline-code block to show detail information about a Customer, make sure input text elements is used to display the content of the Customer (you will later in the lab update the Customer). Set the name attribute of the input text element to the same name as the property of the Customer object it should display. The CustomerID should be displayed as a simple text, and also be a value of an input hidden field with the name “CustomerID”. The reason why you will use a hidden field with the CustomerID, is because you will later use the MVC Frameworks “databinding” feature.

    Note: The Customer object has several properties, and to make this lab simple you can only use some of them, CustomerID, CompanyName, ContactName and Phone.

    Leave the <Form> elements action attribute empty at the moment.

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Customer.aspx.cs" Inherits="CustomerApp.Views.Customer.Customer" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form method="post" action="">
            <table>
                <tr>
                    <td>Customer ID:</td>
                    <td><%= Html.Encode(ViewData.CustomerID) %></td>
                </tr>
                <tr>
                    <td>Company name:</td>
                    <td><input type="text" name="CompanyName" value="<%= Html.Encode(ViewData.CompanyName) %>" /></td>
                </tr>
                <tr>
                    <td>Contact Name:</td>
                    <td><input type="text" name="ContactName" value="<%= Html.Encode(ViewData.ContactName) %>" /></td>
                </tr>
                <tr>
                    <td>Phone:</td>
                    <td><input type="text" name="Phone" value="<%= Html.Encode(ViewData.Phone) %>" /></td>
                </tr>
    
            </table>
    
            <input type="hidden" name="CustomerID" value="<%= Html.Encode(ViewData.CustomerID) %>" />
            
        </form>
    </body>
    </html>
    


     

    Note: Instead of writing the whole <input> element, you can also use the Html help method:


    <%
    = Html.TextBox("CompanyName", ViewData.CompanyName) %>


    This method will render the following output:


    <input type=”text” size=”20” name=”CompanyName” id=”CompanyName” value=”My Company”/>


    Writing HTML will give you more control over the HTML which will be sent to the client.

    Save your View and build your solution. Start the application and to the end of the URL enter “Customer/View/ALFKI”. The URL will look something like this: http://localhost:<port number>/Customer/View/ALFKI. The Customer controller will be used and its Action method View will be called based on the route in global.asax the value after the specified Action method will be passed as an argument to the specified Action method. The argument is mapped to the argument with the name “ID”.

    If everything works, you will now see a detail view over the Customer with the CustomerID “ALFKI”.


    14. Open the Customers.aspx View and make sure the listed CustomerID instead will be a HyperLink, which will have the following URL pattern: “/Customer/View/<CustomerID>”.


    <%
    @ Page Language="C#" AutoEventWireup="true" CodeBehind="Customers.aspx.cs" Inherits="CustomerApp.Views.Customer.Customers" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title></title> </head> <body> <div> <table> <% foreach ( var customer in ViewData) { %> <tr> <td> <a href="/Customer/View/<%=customer.CustomerID %>"><%=customer.CustomerID %></a> </td> <td><%=Html.Encode(customer.ContactName) %></td> </tr> <% } %> </table> </div> </body> </html>


    Instead of writing the <a> element you can use the Html helper method to let it create an RouteLink, for example like this:

     


    <%=Html.RouteLink(ViewData.CustomerID, "Default", new { ID = ViewData.CustomerID, Controller="Home", Action="View" }) %>
     

    When you use the MapRoute method to create a route in global.asax, you give the route a name, for example the default route has the name "Default". When you use the RouteLink method, you can specify the name of the route, the RouteLink method generates a HyperLink. The example above will use the Default route. The result of the above example will be:

    <a href="/Home/View/AFLK">AFLK</a>

    Note: In a future release of the MVC Framework, you don't need to pass the Controller and the Action to the RouteLink.


    Make sure you have saved all files, compile and run the application. To the end of the URL add “Customer/List” and press enter. The URL will look something like this: http://localhost:<port number>/Customer/List.

    If everything works correct, you will now see a list of Customers and the CustomerID will not be a HyperLink. Press on a CustomerID and make sure it will navigate to the Customer View and display detail information about the selected Customer.

    Note: The URL of the HyperLink’s href attribute does not point to a specific file, instead if will point to the Controller and the Action method to be executed when it’s pressed.


    15. Add a new Action method to the CustomerController and name it “Remove”. Make sure it takes an ID of type string as an argument. Use LINQ to SQL to remove a Customer with the CustomerID matches the value of the ID argument. To Remove a Customer you first need to retrieve the Customer object, and then use the method DeleteOnSubmit method of the Customers property of the NorthwindDataContext object. The DeleteOnSubmit takes a Customer object as an argument. To execute the Delete, you need to call the SubmitChanges method of the NorthwindDataContext object.

    Note: Both the View method and the Remove method will get a specific Customer by CustomerID, so you can do some refactoring here and use Extract method to extract code which will get the Customer by CustomerID and put it into a new method, and reuse that method both in the View and Remove Action method. To use the Refactoring feature within Visual Studio, mark the code you want to extract to a method and right click on the selected code block. Select Refactoring and Extract method option. Give the new method a name and press the OK button.

    If you decide to use the Refactoring feature you can mark the following code in the View method:


    Customer customer = (from c in northwindDataContext.Customers
                         where c.CustomerID == ID
                         select c).FirstOrDefault();


    Righ click on the selected code and select Refactoring and Extract method. Give it the name “GetCustomerByID” and press the OK button. If you get an alert box, just press “Yes” to ignore it.

    You should now have a new method with the name GetCustomerByID which the View method will make a call to.

    In the Remove method, make a call to the GetCustomerByID to get the Customer object to delete. If the application fails to remove a Customer, throw an exception. If the remove was successfully, make a call to RedirectToAction to redirect to the Action with the name “List”. This will make sure the List method of the CustomerController will be called.


    public
    ActionResult Remove(string ID) { Customer customer = GetCustomerByID(ID); northwindDataContext.Customers.DeleteOnSubmit(customer); try { northwindDataContext.SubmitChanges(); return RedirectToAction("List"); } catch (Exception e) { throw new ApplicationException(string.Format("Can't remove the Customer {0}", ID), e); } }


    16. Next step is to add a HyperLink to the Customers View, and set the URL to “/Customer/Remove/<CustomerID>” for each Customer. The name of the HyperLink should be “Remove” and can be placed before the CustomerID HyperLink. When you press the HyperLink, the Remove method of the CustomerController will be called and it will remove the Customer.


    <%
    @ Page Language="C#" AutoEventWireup="true" CodeBehind="Customers.aspx.cs" Inherits="CustomerApp.Views.Customer.Customers" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title></title> </head> <body> <div> <table> <% foreach ( var customer in ViewData) { %> <tr> <td> <a href="/Customer/Remove/<%=customer.CustomerID %>">Remove</a>&nbsp; <a href="/Customer/View/<%=customer.CustomerID %>"><%=customer.CustomerID %></a> </td> <td><%=Html.Encode(customer.ContactName) %></td> </tr> <% } %> </table> </div> </body> </html>


    Build the project and run the application, enter the URL to list Customers (By now you should know the URL). Press one of the Remove HyperLink. You will probably get a SQL Exception about reference problems. You aren’t going to resolve that exception. It will indicate that the remove was executed and in this lab you can be satisfied with that.


    17. Add an Update method to the CustomerController, make sure it takes a argument with the name customerID and of type String. Use the customerID to call the GetCustomerByID method to retrieve the Customer from the database. Update the Customer with the new information and use the RedirectToAction method to redirect to the “List” action.

    Note: When using LINQ to SQL we need to get a Customer which is attached to a DataContext, which is the reason why you need to get the Customer. Another reason is also to make it easy to handle concurrency issues etc.

    Use the BindingHelperExtension class’s UpdateFrom method to set the Customer objects properties out from the Reuqest.Form collection.

    Note: The BindingHelperExtension’s UpdateFrom method will get the value out from an input field with the same name as the property of the object passed to the UpdateFrom method and set the value to the object. In the Customer View, there were input fields with the same name as the properties of the Customer object, so those values will be “mapped” to the Customer object you will pass into the UpdateFrom method.


    public ActionResult Update(string customerID)
    {
        Customer customer = GetCustomerByID(customerID);
    
        BindingHelperExtensions.UpdateFrom(customer, Request.Form);
    
        try
        {
            northwindDataContext.SubmitChanges();
        }
        catch (Exception e)
        {
            throw new ApplicationException(
                    string.Format("Can't update customer {0}", customerID)
                    , e);
        }
    
        return RedirectToAction("List");
    }

     

    Note: Values of input fields on a View which has the same name as the arguments of the Update action method will be passed as a value to the respective argument. So in this case you have an input hidden field with the name CustomerID on the View, the value of that field, will be passed as a value to the Update method. So instead of using the UpdateFrom method of the BindingHelperExtensions, you could use arguments for all input fields.

    If you want to learn more about the BindingHeperExtension class, you can read my post "ASP.Net MVC Framework 2 - The BindingHelperClass (UI-mapper)".


    18. Open the Customer View and change the <form> element’s action argument to call the Update method of the CustomerController “/Customer/Update”. Add a Submit button to the View and give it the text value “Update”.

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Customer.aspx.cs" Inherits="CustomerApp.Views.Customer.Customer" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form method="post" action="/Customer/Update">
            <table>
                <tr>
                    <td>Customer ID:</td>
                    <td><%= Html.Encode(ViewData.CustomerID) %></td>
                </tr>
                <tr>
                    <td>Company name:</td>
                    <td><input type="text" name="CompanyName" value="<%= Html.Encode(ViewData.CompanyName) %>" /></td>
                </tr>
                <tr>
                    <td>Contact Name:</td>
                    <td><input type="text" name="ContactName" value="<%= Html.Encode(ViewData.ContactName) %>" /></td>
                </tr>
                <tr>
                    <td>Phone:</td>
                    <td><input type="text" name="Phone" value="<%= Html.Encode(ViewData.Phone) %>" /></td>
                </tr>
    
            </table>
    
            <input type="hidden" name="CustomerID" value="<%= Html.Encode(ViewData.CustomerID) %>" />
            
            <input type="submit" value="Update" />
        </form>
    </body>
    </html>
    


    Build the solution and run the application. Enter the URL to list all Customers “Customer/List” and select a Customer from the list. Update the Customer and press the Update button. When the Update button is pressed, the customer will be updated and you will be redirected to the List action so the List of Customer will be displayed.

    Note: Instead of using an input field with the name CustomerID, you could also set the action attribute to “/Customer/Update/<the customerID>”.

    The last thing to do now is to create an ActionFilter for the Remove action method. You only want to make sure the user with the name “student” will make a call to the Remove action method.


    19. Add a new class to the Model folder. Name it “AuthorizedFilterAttribute”. Make sure it inherits from the base class ActionFilterAttribute. The ActionFilterAttribute is located in the namespace “System.Web.Mvc”.

    The ActionFilter can be used to perform pre- and post action. You can use FilterAction to cancel an execution of an Action method, or you can use it to log information etc. The ActionFilter can now in pre-release of the Preview 3 of the ASP.Net MVC Framework also get access to the ActionResult returned from the Action method.

    The ActionFilter AuthorizedFilter will be used to only make sure the user “student” has access to the Remove method, if not a SecurityException will be thrown.

    To implement code for a pre action, override the OnActionExecuting method of the ActionFilterAttribute class. To perform a post action, override the OnActionExecuted method. To get the current user you can use the filterContext arugment’s HttpContext property and its User.Identity.name property. You don’t need to cancel the action of the AuthorizedFilter when you throw an exception. To cancel, you can set the filterContext Cancel property to true.


    using
    System.Security; namespace CustomerApp.Models { public class AuthorizedFilter : ActionFilterAttribute { public override void OnActionExecuting(FilterExecutingContext filterContext) { if (filterContext.HttpContext.User.Identity.Name != "student") throw new SecurityException(
    "You aren't allowed to call this action!"); } } }

     

    Apply the AuthorizedFilter to the Remove method.

    [AuthorizedFilter]
    public void Remove(string ID)


    Note: If you want to make sure the filter will be used for every Action method of a Controller, you can add the attribute to the Controller’s class.

    If you want to test if the filter works, add a breakpoint to the OnActionExecuting method and run the application in debug mode. List the Customers and press the Remove HyperLink, or you can simply run the application, list the customers and press the Remove Hyperink, it should probably give you a SecurityException. If you want to learn more about ActionFilter, you can read my post "ASP.Net MVC Framework 2 - Interception and creating a Role Action Filter", I will later create a new post about the ActionFilter in the pre-release of Preview 3.

    In this step by step guide you have learned how to create a simple application by using the ASP.Net MVC Framework pre-release of Preview 3. You have learned how to create a Controller, Views and also ActionFilter to intercept pre actions to a Action method.

    Read more...

  • ASP.Net MVC Framework Preview 2 - A step by step guide to create a simple Web Application

    UPDATE: When I cerated a new post on my blog about the pre-release of Preview 3, I replaced this one with the new post. I did my best to recover the content. Sorry!

    In this post you will learn how to use most of the new features in the Preview 2 version of the ASP.NET Framework, you will also get a basic understanding about how to use LINQ to SQL. This step by step guide shouldn't be used as a "best way to create and design" a web applications by using the ASP.NET MVC Framework, this guide should only be used to get started with the MVC Framework in a fast and easy way and learn different ways to use some of the features shipped with the ASP.Net MVC Framework Preview 2.

    To get the pre-release version, you can download it from here.

    In this step by step guide you are going to create a web based application where you will be able to list and modify customers. This step by step guide will use C# 3.0 and the Northwind database.


    1. Open Visual Studio 2008


    2. Create a new Project and select the ”ASP.NET MVC Web Project” project and name it to “CustomerApp”.


    3. Open global.asax and walk through the code. In Global.asax you can specify your routes. In this step by step guide you will use the default settings.


    The first thing to do is to create your business objects (your Model) which your Controllers will interact with. In this step by step guide you will use LINQ to SQL, even if it’s not advisable to generate domain models out from a data source you will learn how to do it, only to get up and running fast.

    Note: The business objects belongs to the Model in the MVC pattern.


    4. Right click on the Models folder in the Solution Explorer and select Add > New Item.

    Select the “LINQ to SQL Classes” template and name the file to “Northwind.dbml” and press the Add button.

    To create your Model out from a data source you need to add a database connection to Visual Studio. This can be done by using the Server Explorer. In the Solution Explorer, right click on the Data Connections node and select Add Connection. Enter the following information to connect to the Northwind database:

    Server Name: (local)

    Select the Northwind database, test the connection and press OK if you were able to connect to the database.

    A connection to the Northwind database will now be added under the “Data Connections” node in the Server Explorer. Expand the database and the Tables nodes; drag out the Customer table into the design view of the Northwind.dbml file. Save the file. When you save the file, LINQ to SQL will generate a Customer object for you where the columns from the Customers table will be added as properties to the Customer object. LINQ to SQL will also generate a DataContext object (NorthwindDataContext) which you will use later to access your information from the data source. Expand the Northwind.dbml file in the Solution Explorer, double click on the Northwind.designer.cs file and walk through the code. LINQ to SQL uses attributes to map classes to a table.

    Now it’s time to create the Controller which you are going to use in this application.


    5. Right click on the Controllers folder in the Solution Explorer and add a new item and select the “MVC Controller Class” template,  name it to “CustomerController”.


    6. Add a private field of the type NorhwindDataContext to the Controller and name the field to “northwindDataContext”. Set the field to an instance of the NorthwindDataContext object.

    Note: The NorthwindDataContext class will exist in the CustomerApp.Models namespace.


    using
    CustomerApp.Models; namespace CustomerApp.Controllers { public class CustomerController : Controller, IDisposable { private NorthwindDataContext northwindDataContext = new NorthwindDataContext(); //... } }


    7. Make sure the CustomerController implements the IDisposable interface, and implement the Dispose method and make sure it will make a call to the northwindDataContext’s Dispose method. This will make sure the NorthwindDataContext’s Dispose method will be called when the Controller have been used.


    public class
    CustomerController : Controller, IDisposable { private NorthwindDataContext northwindDataContext = new NorthwindDataContext(); //... public void Dispose() { this.northwindDataContext.Dispose(); } }


    8. Add an Action method and name it to “List”. The List action will retrieve all Customers from the Customers table of the Northwind database. LINQ to SQL will be used to get all the Customers, order the Customers by CompanyName. When all customers are retrieved make sure to render a View with the name “Customers” (The View will be added later to the project), the View should render a generic list of Customer objects.


    public void
    List() { List<Customer> customers = (from customer in northwindDataContext.Customers orderby customer.CompanyName select customer).ToList(); RenderView("Customers", customers); }


    9. Create a View with the name “Customers” which will render the generic list of Customer objects. To add a View, right click on the Views folder and add a new folder with the name “Customer”. Right click on the Customer folder and add a new item, select the “MVC View Page” template from the "My Template" section and name the View to “Customers”. Make sure the View data inherits from ViewPage<List<CustomerApp.Models.Customer>>. This will make sure the Model which is passed as an argument to the RenderView method is a known and typed for the View. Open the file Customers.aspx.cs file, replace so the page inherits from ViewPage<List<CustomerApp.Models.Customer>> instead of ViewPage.


    public partial class
    Customers : ViewPage<List<CustomerApp.Models.Customer>> { }


    10. Add code to render a list of Customers to the View, make sure the CustomerID and ContactName are listed. Open the Customer.aspx file, add an inline-code block and use foreach to iterate through the Customers, use the ViewData property to get access to the generic list of Customer objects.


    <%
    @ Page Language="C#" AutoEventWireup="true" CodeBehind="Customers.aspx.cs" Inherits="CustomerApp.Views.Customer.Customers" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title></title> </head> <body> <div> <table> <% foreach ( var customer in ViewData) { %> <tr> <td><%=Html.Encode(customer.CustomerID) %></td> <td><%=Html.Encode(customer.ContactName) %></td> </tr> <% } %> </table> </div> </body> </html>


    Make sure you have saved all files, compile and run the application. To the end of the URL add “Customer/List” and press enter. The URL will look something like this: http://localhost:<port number>/Customer/List.

    Your application will now make sure the Controller “CustomerController” will be used and also the Action method “List” will be invoked. If everything works, you will now see a list of CustomerID and ContactName.

    Note: The route that was defined in global.asax looks like this:


    {controller}/{action}/{id}


    When you enter a URL like “Customer/List”, the Customer will be the name of the Controller to be used, and the List the name of the Action method to be executed, the id in the route will be empty and will be ignored.


    11. Add a new Action method to the CustomerController and name it to “View”. The View method should have one argument with the name ID and the type of String. Make sure the method will use LINQ to SQL to get a Customer from the Customers table which matches the CustomerID passed as an argument. If a customer is not found throw an exception. Make sure to render a View with the name “Customer”. The View should ender a detail view of a Customer.

    public void View(string ID)
    {
        Customer customer = (from c in northwindDataContext.Customers
                             where c.CustomerID == ID
                             select c).FirstOrDefault();
    
        if (customer == null)
            throw new ApplicationException(
                        String.Format("Can't find a Customer with the CustomerID {0}", ID));
    
        RenderView("Customer", customer);
    }


    12. Add a new View to the Views/Customer folder and name it “Customer”. Make sure the Customer View will inherit form the ViewPage<CustomerApp.Models.Customer> class.


    public partial class
    Customer : ViewPage<CustomerApp.Models.Customer> { }


    13. Open the Customer.aspx page and add inline-code block to show detail information about a Customer, make sure input text elements is used to display the content of the Customer (you will later in the lab update the Customer). Set the name attribute of the input text element to the same name as the property of the Customer object it should display. The CustomerID should be displayed as a simple text, and also be a value of an input hidden field with the name “CustomerID”. The reason why you will use a hidden field with the CustomerID, is because you will later use the MVC Frameworks “databinding” feature.

    Note: The Customer object has several properties, and to make this lab simple you can only use some of them, CustomerID, CompanyName, ContactName and Phone.

    Leave the <Form> elements action attribute empty at the moment.

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Customer.aspx.cs" Inherits="CustomerApp.Views.Customer.Customer" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form method="post" action="">
            <table>
                <tr>
                    <td>Customer ID:</td>
                    <td><%= Html.Encode(ViewData.CustomerID) %></td>
                </tr>
                <tr>
                    <td>Company name:</td>
                    <td><input type="text" name="CompanyName" value="<%= Html.Encode(ViewData.CompanyName) %>" /></td>
                </tr>
                <tr>
                    <td>Contact Name:</td>
                    <td><input type="text" name="ContactName" value="<%= Html.Encode(ViewData.ContactName) %>" /></td>
                </tr>
                <tr>
                    <td>Phone:</td>
                    <td><input type="text" name="Phone" value="<%= Html.Encode(ViewData.Phone) %>" /></td>
                </tr>
    
            </table>
    
            <input type="hidden" name="CustomerID" value="<%= Html.Encode(ViewData.CustomerID) %>" />
            
        </form>
    </body>
    </html>
    


    Note: Instead of writing the whole <input> element, you can also use the Html help method:


    <%
    = Html.TextBox("CompanyName", ViewData.CompanyName) %>


    This method will render the following output:


    <input type=”text” size=”20” name=”CompanyName” id=”CompanyName” value=”My Company”/>


    Writing HTML will give you more control over the HTML which will be sent to the client.

    Save your View and build your solution. Start the application and to the end of the URL enter “Customer/View/ALFKI”. The URL will look something like this: http://localhost:<port number>/Customer/View/ALFKI. The Customer controller will be used and its Action method View will be called based on the route in global.asax the value after the specified Action method will be passed as an argument to the specified Action method. The argument is mapped to the argument with the name “ID”.

    If everything works, you will now see a detail view over the Customer with the CustomerID “ALFKI”.


    14. Open the Customers.aspx View and make sure the listed CustomerID instead will be a HyperLink, which will have the following URL pattern: “/Customer/View/<CustomerID>”.


    <%
    @ Page Language="C#" AutoEventWireup="true" CodeBehind="Customers.aspx.cs" Inherits="CustomerApp.Views.Customer.Customers" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title></title> </head> <body> <div> <table> <% foreach ( var customer in ViewData) { %> <tr> <td> <a href="/Customer/View/<%=customer.CustomerID %>"><%=customer.CustomerID %></a> </td> <td><%=Html.Encode(customer.ContactName) %></td> </tr> <% } %> </table> </div> </body> </html>


    Instead of writing the <a> element you can use the Html helper method to let it create an ActionLink, for example like this:


    <%
    = Html.ActionLink<CustomerApp.Controllers.CustomerController>(a => a.View(customer.CustomerID), customer.CustomerID) %>


    Make sure you have saved all files, compile and run the application. To the end of the URL add “Customer/List” and press enter. The URL will look something like this: http://localhost:<port number>/Customer/List.

    If everything works correct, you will now see a list of Customers and the CustomerID will not be a HyperLink. Press on a CustomerID and make sure it will navigate to the Customer View and display detail information about the selected Customer.

    Note: The URL of the HyperLink’s href attribute does not point to a specific file, instead if will point to the Controller and the Action method to be executed when it’s pressed.


    15. Add a new Action method to the CustomerController and name it “Remove”. Make sure it takes an ID of type string as an argument. Use LINQ to SQL to remove a Customer with the CustomerID matches the value of the ID argument. To Remove a Customer you first need to retrieve the Customer object, and then use the method DeleteOnSubmit method of the Customers property of the NorthwindDataContext object. The DeleteOnSubmit takes a Customer object as an argument. To execute the Delete, you need to call the SubmitChanges method of the NorthwindDataContext object.

    Note: Both the View method and the Remove method will get a specific Customer by CustomerID, so you can do some refactoring here and use Extract method to extract code which will get the Customer by CustomerID and put it into a new method, and reuse that method both in the View and Remove Action method. To use the Refactoring feature within Visual Studio, mark the code you want to extract to a method and right click on the selected code block. Select Refactoring and Extract method option. Give the new method a name and press the OK button.

    If you decide to use the Refactoring feature you can mark the following code in the View method:


    Customer customer = (from c in northwindDataContext.Customers
                         where c.CustomerID == ID
                         select c).FirstOrDefault();
    if (customer == null)
        throw new ApplicationException(
                    String.Format("Can't find a Customer with the CustomerID {0}", ID));

    Righ click on the selected code and select Refactoring and Extract method. Give it the name “GetCustomerByID” and press the OK button. If you get an alert box, just press “Yes” to ignore it.

    You should now have a new method with the name GetCustomerByID which the View method will make a call to.

    In the Remove method, make a call to the GetCustomerByID to get the Customer object to delete. If the application fails to remove a Customer, throw an exception. If the remove was successfully, make a call to RedirectToAction to redirect to the Action with the name “List”. This will make sure the List method of the CustomerController will be called.


    public void Remove(string ID)
    {
        Customer customer = GetCustomerByID(ID);
    
        northwindDataContext.Customers.DeleteOnSubmit(customer);
    
        try
        {
            northwindDataContext.SubmitChanges();
            RedirectToAction("List");
        }
        catch (Exception e)
        {
            throw new ApplicationException(string.Format("Can't remove the Customer {0}", ID), e);
        }
    }


    16. Next step is to add a HyperLink to the Customers View, and set the URL to “/Customer/Remove/<CustomerID>” for each Customer. The name of the HyperLink should be “Remove” and can be placed before the CustomerID HyperLink. When you press the HyperLink, the Remove method of the CustomerController will be called and it will remove the Customer.


    <%
    @ Page Language="C#" AutoEventWireup="true" CodeBehind="Customers.aspx.cs" Inherits="CustomerApp.Views.Customer.Customers" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title></title> </head> <body> <div> <table> <% foreach ( var customer in ViewData) { %> <tr> <td> <a href="/Customer/Remove/<%=customer.CustomerID %>">Remove</a>&nbsp; <a href="/Customer/View/<%=customer.CustomerID %>"><%=customer.CustomerID %></a> </td> <td><%=Html.Encode(customer.ContactName) %></td> </tr> <% } %> </table> </div> </body> </html>


    Build the project and run the application, enter the URL to list Customers (By now you should know the URL). Press one of the Remove HyperLink. You will probably get a SQL Exception about reference problems. You aren’t going to resolve that exception. It will indicate that the remove was executed and in this lab you can be satisfied with that.


    17. Add an Update method to the CustomerController, make sure it takes a argument with the name customerID and of type String. Use the customerID to call the GetCustomerByID method to retrieve the Customer from the database. Update the Customer with the new information and use the RedirectToAction method to redirect to the “List” action.

    Note: When using LINQ to SQL we need to get a Customer which is attached to a DataContext, which is the reason why you need to get the Customer. Another reason is also to make it easy to handle concurrency issues etc.

    Use the BindingHelperExtension class’s UpdateFrom method to set the Customer objects properties out from the Reuqest.Form collection.

    Note: The BindingHelperExtension’s UpdateFrom method will get the value out from an input field with the same name as the property of the object passed to the UpdateFrom method and set the value to the object. In the Customer View, there were input fields with the same name as the properties of the Customer object, so those values will be “mapped” to the Customer object you will pass into the UpdateFrom method.


    public void Update(string customerID)
    {
        Customer customer = GetCustomerByID(customerID);
        
        BindingHelperExtensions.UpdateFrom(customer, Request.Form);
    
        northwindDataContext.SubmitChanges();
    
        RedirectToAction("List");
    }

     

    Note: Values of input fields on a View which has the same name as the arguments of the Update action method will be passed as a value to the respective argument. So in this case you have an input hidden field with the name CustomerID on the View, the value of that field, will be passed as a value to the Update method. So instead of using the UpdateFrom method of the BindingHelperExtensions, you could use arguments for all input fields.

    If you want to learn more about the BindingHeperExtension class, you can read my post "ASP.Net MVC Framework 2 - The BindingHelperClass (UI-mapper)".


    18. Open the Customer View and change the <form> element’s action argument to call the Update method of the CustomerController “/Customer/Update”. Add a Submit button to the View and give it the text value “Update”.

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Customer.aspx.cs" Inherits="CustomerApp.Views.Customer.Customer" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form method="post" action="/Customer/Update">
            <table>
                <tr>
                    <td>Customer ID:</td>
                    <td><%= Html.Encode(ViewData.CustomerID) %></td>
                </tr>
                <tr>
                    <td>Company name:</td>
                    <td><input type="text" name="CompanyName" value="<%= Html.Encode(ViewData.CompanyName) %>" /></td>
                </tr>
                <tr>
                    <td>Contact Name:</td>
                    <td><input type="text" name="ContactName" value="<%= Html.Encode(ViewData.ContactName) %>" /></td>
                </tr>
                <tr>
                    <td>Phone:</td>
                    <td><input type="text" name="Phone" value="<%= Html.Encode(ViewData.Phone) %>" /></td>
                </tr>
    
            </table>
    
            <input type="hidden" name="CustomerID" value="<%= Html.Encode(ViewData.CustomerID) %>" />
            
            <input type="submit" value="Update" />
        </form>
    </body>
    </html>
    


    Build the solution and run the application. Enter the URL to list all Customers “Customer/List” and select a Customer from the list. Update the Customer and press the Update button. When the Update button is pressed, the customer will be updated and you will be redirected to the List action so the List of Customer will be displayed.

    Note: Instead of using an input field with the name CustomerID, you could also set the action attribute to “/Customer/Update/<the customerID>”.

    The last thing to do now is to create an ActionFilter for the Remove action method. You only want to make sure the user with the name “student” will make a call to the Remove action method.


    19. Add a new class to the Model folder. Name it “AuthorizedFilterAttribute”. Make sure it inherits from the base class ActionFilterAttribute. The ActionFilterAttribute is located in the namespace “System.Web.Mvc”.

    The ActionFilter can be used to perform pre- and post action. You can use FilterAction to cancel an execution of an Action method, or you can use it to log information etc. 

    The ActionFilter AuthorizedFilter will be used to only make sure the user “student” has access to the Remove method, if not a SecurityException will be thrown.

    To implement code for a pre action, override the OnActionExecuting method of the ActionFilterAttribute class. To perform a post action, override the OnActionExecuted method. To get the current user you can use the filterContext arugment’s HttpContext property and its User.Identity.name property. You don’t need to cancel the action of the AuthorizedFilter when you throw an exception. To cancel, you can set the filterContext Cancel property to true.


    using
    System.Security; namespace CustomerApp.Models { public class AuthorizedFilter : ActionFilterAttribute { public override void OnActionExecuting(FilterExecutingContext filterContext) { if (filterContext.HttpContext.User.Identity.Name != "student") throw new SecurityException(
    "You aren't allowed to call this action!"); } } }

     

    Apply the AuthorizedFilter to the Remove method.

    [AuthorizedFilter]
    public void Remove(string ID)


    Note: If you want to make sure the filter will be used for every Action method of a Controller, you can add the attribute to the Controller’s class.

    If you want to test if the filter works, add a breakpoint to the OnActionExecuting method and run the application in debug mode. List the Customers and press the Remove HyperLink, or you can simply run the application, list the customers and press the Remove Hyperink, it should probably give you a SecurityException. If you want to learn more about ActionFilter, you can read my post "ASP.Net MVC Framework 2 - Interception and creating a Role Action Filter".

    In this step by step guide you have learned how to create a simple application by using the ASP.Net MVC Framework Preview 2. You have learned how to create a Controller, Views and also ActionFilter to intercept pre actions to a Action method.

    Read more...