RSS 2.0
# Monday, February 07, 2011

In our previous post, we very quickly put together a site using asp.net mvc, Entity Framework code first and MvcScaffolding templates.  That got it up and running, but of course there’s still plenty to do.  But before we get going in more development, let’s take a step back and look over the files so we understand what is going on.

So, how does MVC work? MVC stands for Model View Controller.  The pattern lends itself very well to having a good separation of concerns. That of course creates a very testable architecture. One of the goals for asp.net mvc was to use convention over configuration. How many times have you created a webforms application and had a ton of configuration in web.config?  Webforms straight out of the box uses a good deal of configuration just to get going.  MVC is structured in a predictable way.  There is a controllers directory where all the controllers are to be housed and a views directory where all the views are to be housed.  Routing is used to define how a URL is parsed out to map to the controllers.  So, our default route for KimmysCookbook.com is:

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Recipe", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

What this is saying is that when a URL comes in, the first part should map to a controller, the second part to an action on that controller and the third part is a parameter that will be passed to that action.  The last part defines the defaults.  If no controller is is passed then the default is Recipe.  So in our case, when a user navigates to http://www.kimmyscookbook.com mvc will map that to http://www.kimmyscookbook.com/Recipe/Index .  Notice how easy that URL is to read.  That URL tells the MVC framework to look for a controller named RecipeController (the controller prefix is assumed by the framework) and it looks in the Controllers directory off the root of the site for it.  Once that type is loaded, it will look for the Index method within it and execute that resource.  Notice I said resource.  That’s an important distinction.  We are not serving up pages, rather we are serving resources.  So far the only resource we have returned are Views, however we could return just plain content (text), JSON, a file or even write our out ActionResult.  Just derive from ActionResult.

Our current Index method on the Recipe controller is this:

        public ViewResult Index()
        {
            return View(this.repository.GetAllRecipes());
        }

This is returning a View.  By default, the framework is going to seek out a view in the Views/Recipe directory.  Again, convention over configuration.  It will also search the Shared directory as well.

Our model in this case is an IEnumerable<Recipe>. So we are passing a list of Recipes to the view.  The view’s job is simply to display the model passed to it.  The view is intended to be very simple, therefore you don’t have a code behind file as you do in webforms. 

Monday, February 07, 2011 10:48:40 PM UTC  #    Comments [0] -
mvc
# Thursday, January 20, 2011

Ok, well, for whatever reason, I wasn’t able to get the old project working with MvcScaffolding after updating to the RTM of MVC 3.  I had even run the upgrade tool.  We are and were dealing with beta software, sometimes that’s what happens.  Thankfully we weren’t too far along.  So, what I’ve done is created a new project and simply added all our model classes to the new project.

I then reinstalled our packages from NuGet:

image

image

Now we will do some scaffolding.

image

Change the default route to point to our Recipe Controller:

image

And wa-la, we’ve got a running application.

image

Since we never defined a connection string for the application, it created a new database in our Sql Server Express instance with the fully qualified name of the context class.

image

So you can see that outside of create our model classes, everything else can be automated and done very quickly.  Understanding what is actually going on is important, so next we’ll look in more detail at the files that were created.

Technorati Tags: ,
Thursday, January 20, 2011 10:52:44 PM UTC  #    Comments [0] -
.NET | Entity Framework | mvc | SQL Server | Visual Studio
# Monday, January 17, 2011

Ok, so MVC 3 just RTM’d, so we are going to take a step back and upgrade.  First off, go uninstall the RC – be sure to uninstall both mvc 3 and the vs tools.  Once that is done you can open Web PI and install mvc 3.  If you don’t have Web PI yet, you can get 3.0 from here. http://www.microsoft.com/web/downloads/platform.aspx 

In reading the release notes, which you can download here, seems we shouldn’t have any issues moving this project forward since we are so new into it. The install takes quite a while because it does some updates to Visual Studio as well.

Monday, January 17, 2011 5:57:01 PM UTC  #    Comments [0] -
mvc
# Wednesday, January 12, 2011

Ok, so maybe that’s not correct … do Roman numerals even have decimals.  Hmmm… maybe I should have paid a bit more attention in that class. In Part I we set up our classes and data access “layer”.  Thanks to ErikEJ letting me know of a provider that he – uh – provided for SQL CE, we’ll integrate that in.  Since this wasn’t in the original plan, we’ll call this I.V or 1.5.  Smile

You can go get the files from here.  I’m just going to include the files rather than the binary.  I found an issue in the SqlCeMembershipUtils.cs file in the CreateDatabaseIfNeeded method.  It has to do with how the path shows up.  When checking for the file, the connection returns the following for the Database (path) property, which of course is not the path to the actual sdf file.  The connection works however.

image

So, I’ve modified that method like so:

        public static void CreateDatabaseIfRequired(string connection)
        {
            string dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory") as string;
            string physConnectionString = connection.Replace("|DataDirectory|", dataDirectory);
            string[] parts = connection.Split('|');
            string physFileString = Path.Combine(dataDirectory, parts[parts.Length - 1]);

            string sdfPath = string.Empty;
            lock (_lock)
            {
                using (var testConn = new SqlCeConnection(physConnectionString))
                {
                    sdfPath = testConn.Database;
                }
                if (string.IsNullOrWhiteSpace(sdfPath))
                    return;

                if (!System.IO.File.Exists(physFileString))
                {
                    //OK, try to create the database file
                    using (var engine = new SqlCeEngine(connection))
                    {
                        engine.CreateDatabase();
                    }
                }
                ValidateDatabase(connection);
            }
        }

You will of course need to modify the connections in web.config for the membership provider and add using System.IO; to the top.  The other option would be to skip the file check and just eat the exception if it’s because of the file already existing.

Technorati Tags: ,
Wednesday, January 12, 2011 7:42:48 PM UTC  #    Comments [2] -
Entity Framework | mvc
# Saturday, January 08, 2011

If you haven’t already, go install mvc 3 RC.  This will also install NuGet which we will be using.  You can read more about mvc 3 and NuGet on ScottGu’s blog.

Create a new MVC 3 Web Application and use Razor for the view engine.  Probably a good idea to tick on the unit test box to create unit tests.

image

Next get the Package Manager Console open.  View | Other Windows | Package Manager Console

Now we want to install the Entity Framework Code First libraries.  NuGet makes this very easy:

image

The console window support auto-completion, so just type Ins [TAB] and a list of options will show. Choose Install-Package then type EFC [TAB] to choose through a list of packages.  Couldn’t be easier.  I’m not going to go into details about what that does, you can read all about it in ScottGu’s posts and the video of Scott Hanselman’s talk.

In our first post in the series, our first goal was to make a quick site.  Doing it quickly means we are going to let the Entity Framework create the database for us.  We will also be using SQL CE so there won’t be a full database dependency.  SQL CE 4.0 is now bin deployable, so we can just copy it up and it’ll work.

EF, much like MVC, uses convention over configuration.  So, since our context (code to follow) is going to be named Cookbook, if we create a connection string entry called Cookbook, EF will automatically use that.

  <connectionStrings>
    <
add name="Cookbook" connectionString="Data Source=|DataDirectory|KimmysCookbook.sdf" providerName="System.Data.SqlServerCe.4.0"
/>
  </
connectionStrings>

As an aside, if you don’t create a connectionstring at all, EF CTP5 will create a Sql Server CE 4.0 database under the App_Data directory for you using the fully qualified type name as the name of the database.

Now for our Context class.  We’ll create each of our supporting classes as we go.  Right click on the Models folder and add a class.  As you are typing, as you put in the classes for the generic collections, pressing Ctrl-. will present you with a context of options.  Since the classes won’t exist yet, you can have VS create the classes for you right then.  They will of course be empty, but the shell is there.  VS is also intelligent enough to put them in the same folder as the current class with the same namespace.  So, when you type public DbSet<Recipe, you’ll get a squiggly saying that Recipe doesn’t exist.  Ctrl-. and choose to have it create the class for you.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;

namespace KimmysCookbook.Models
{
    public class Cookbook : DbContext
    {
        public DbSet<Recipe> Recipes { get; set; }
        public DbSet<Ingredient> Ingredients { get; set; }
        public DbSet<Comment> Comments { get; set; }
        public DbSet<Favorite> Favorites { get; set; }
        public DbSet<Tag> Tags { get; set; }
        public DbSet<Rating> Ratings { get; set; }
    }
}

The above context class is all that is needed for data access.

Let’s fill in the rest of our classes.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace KimmysCookbook.Models
{
    public class Recipe
    {
        public int ID { get; set; }
        public Guid UserID { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public long PrepTime { get; set; }
        public long CookTime { get; set; }
        public int Serves { get; set; }
        public string Instructions { get; set; }
        public string IPAddress { get; set; }

        public virtual ICollection<Ingredient> Ingredients { get; set; }
        public virtual ICollection<Tag> Tags { get; set; }
        public virtual ICollection<Comment> Comments { get; set; }
        public virtual ICollection<Rating> Ratings { get; set; }
        public virtual ICollection<Favorite> Favorites { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KimmysCookbook.Models
{
    public class Ingredient
    {
        public int ID { get; set; }
        public int RecipeID { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KimmysCookbook.Models
{
    /// <summary>
    /// This is for user based tagging
    /// </summary>
    public class Tag
    {
        public int ID { get; set; }
        public int RecipeID { get; set; }
        public Guid UserID { get; set; }
        public string Value { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KimmysCookbook.Models
{
    public class Comment
    {
        public int ID { get; set; }
        public int RecipeID { get; set; }
        public Guid UserID { get; set; }
        public string Text { get; set; }
        public string IPAddress { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KimmysCookbook.Models
{
    /// <summary>
    /// This is to tag a recipe as a favorite for a user
    /// </summary>
    public class Favorite
    {
        public int ID { get; set; }
        public int RecipeID { get; set; }
        public Guid UserID { get; set; }
        public DateTime DateFavorited { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KimmysCookbook.Models
{
    public class Rating
    {
        public int ID { get; set; }
        public int RecipeID { get; set; }
        public Guid UserID { get; set; }
        public int Value { get; set; }
        public DateTime RatingDate { get; set; }
        public string IPAddress { get; set; }
    }
}

You’ll notice in the classes that the UserID field is a Guid. In this iteration, we are going to use the Membership provider that is baked into asp.net. In a future release, we plan to use OpenID instead. That being said and to keep it simple, we want to have the membership baked into the database that EF is going to create.  Unfortunately, SQL CE 4 still doesn’t support stored procedures so the current implementation of membership won’t work with it.  According to ScottGu’s post, they are looking into create a set of providers that will work with it. 

Technorati Tags: ,
Saturday, January 08, 2011 8:22:55 PM UTC  #    Comments [2] -
.NET | Entity Framework | mvc | SQL Server
# Monday, December 27, 2010

Years ago I purchased the domain KimmysCookbook.com as a joke.  A friend on facebook had posted a picture of her taking a turkey out of the oven and a bunch of us started commenting on it and eventually the domain came to be.  She is a good cook, the joke wasn’t about her cooking, just about making a cookbook.

Anyway, I never did anything with it really, just posted that picture and let it sit.  Got to thinking that it would be a cool recipe site and with all the new stuff coming out of Redmond recently, why not take the time to build it up piece by piece using these technologies. 

I’ve been toying with the idea for a while, so I’ve already created a database locally for storage, but since we are looking to use new technologies and also doing it on the cheap and fast, we’ll use EF4’s code first ability tied with SQL Server CE 4.

Here’s the path I’m looking to take.  Each of these will be a separate iteration and push to the server.

  1. Quick ASP.net MVC 3 with EF4 code first site
  2. Add Silverlight support for ingredient editing
  3. Add OData support
  4. Silverlight out of browser with touch support
  5. Windows Phone 7 application

As with any project, these items may change as we go along.  Next entry will outline step 1.

Monday, December 27, 2010 7:58:51 PM UTC  #    Comments [0] -
mvc | Silverlight | Windows Phone 7
# Monday, August 02, 2010

Create a new asp.net mvc2 application.  In the Home controller add this method:

public ActionResult Test(string id)
{
    ViewData["Message"] = id;
    return View();
}

 

Right click in the method and Add View.

View will be very simple:

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

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

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

    <h2>Test</h2>

    <h2><%: ViewData["Message"] %></h2>

</asp:Content>

In the master page, add this menu item:

<li><%: Html.ActionLink("Test", "Test", "Home") %></li>

 

Run the application.  When the index page comes up, the “Test” menu item will correctly output as something like: http://localhost:60239/Home/Test

Add something to the end of the url, say “HelloWorld” and the url of the menu item holds the “HelloWorld” (http://localhost:60239/Home/Test/HelloWorld) rather than reverting back to http://localhost:60239/Home/Test like I would expect.  Bug? Or am I missing something?

Technorati Tags:
Monday, August 02, 2010 1:15:09 AM UTC  #    Comments [0] -
mvc
# Tuesday, May 04, 2010

In this post, we are going to demonstrate some simple Ajax updates.  We will be using the AdentureWorks db for this.  You can download it here if you don’t have it.

Launch VS2010 and create a new ASP.NET MVC 2 Application:

image

For this, we’ll skip creating the test project.

Next we’ll use LINQ to SQL to generate some data models.  Right click on the Models node and Add Item (or Ctrl-Shift-A when the node is selected):

image

When the designer comes up, add the Product and ProductCategory tables.

image

In HomeController.cs create a new method called ProductSearch:

We’ll need to use our model, so add

using AWAjaxDemo.Models;

then we’ll add our new method:

public ActionResult ProductSearch(string query)
{
    IList<Product> products = new List<Product>();
    AWModelsDataContext db = new AWModelsDataContext();

    if (!string.IsNullOrWhiteSpace(query))
    {
        products = db.Products.Where(p => p.Name.StartsWith(query)).OrderBy(p => p.Name).ToList();
    }
    else
        products = db.Products.OrderBy(p => p.Name).ToList();

    if (Request.IsAjaxRequest())
        return View("ProductSearchResults", products);
    else

        return View(products);
}

 

We check to see if we have a query value coming in, if we do, we limit our query to names that start with the query. If not, we return them all.  Also note, that we check to see if this is an Ajax call. If someone has javascript off, we still want this to be functional.

Compile the project so we’ll have the model types available to us when we create our partial view.

Right click on Views/Home and add a View.  We’ll call this ProductSearchResults:

image

We’ll simplify the view down a bit to just include a few fields.  Of course, ideally we’d use a view-model for this to limit what data is even available, but that’s not the point of this post.

<%@ Control Language="C#" 
Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<AWAjaxDemo.Models.Product>>" %>

    <table>
        <tr>
            <th>
                Name
            </th>
            <th>
                ProductNumber
            </th>
            <th>
                Color
            </th>
            <th>
                StandardCost
            </th>
            <th>
                ListPrice
            </th>
           
        </tr>

    <% foreach (var item in Model) { %>
    
        <tr>          
            <td>
                <%: item.Name %>
            </td>
            <td>
                <%: item.ProductNumber %>
            </td>
            <td>
                <%: item.Color %>
            </td>
            <td>
                <%: String.Format("{0:F}", item.StandardCost) %>
            </td>
            <td>
                <%: String.Format("{0:F}", item.ListPrice) %>
            </td>
           
        </tr>
    
    <% } %>

    </table>



So, now we have a simplified partial view.

Now we’ll add our main view.  Right-click on the View/Home node and add a strongly typed empty view.  Base it on the AWAjaxDemo.Models.Product type that we did for the partial view.

image

Replace the default code with this:

<%@Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<IEnumerable<AWAjaxDemo.Models.Product>>"%>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
  
Product Search
</asp:Content>
<
asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <
script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"></script>
    <
script src="../../Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
    <
h2>
      
ProductSearch</h2>
  
<% using(Ajax.BeginForm("ProductSearch", new AjaxOptions { UpdateTargetId = "results"}))
       { %>
    Search: <%=Html.TextBox("query")%> <input type="submit" value="Go" />
    <
div id="results">
  
<% Html.RenderPartial("ProductSearchResults", Model); %>
    </div>
  
<%} %>
</asp:Content>

You’ll notice that the two Ajax scripts are referenced.  They are added to mvc 2 applications by default.  The other thing to notice is how the form is constructed.  Normally the Html.BeginForm extension method is used. Here we are using the Ajax.Begin form method and passing it a new instance of AjaxOptions specifying the target to be updated. In our case, the target is the div with the id result.  Our ProductSearchResults partial view will be rendered there after the Ajax call.

That was pretty easy … of course in a production environment, you’d want to be using caching to reduce the database calls.

Technorati Tags: ,
Tuesday, May 04, 2010 1:56:30 AM UTC  #    Comments [0] -
mvc | Visual Studio
# Wednesday, April 14, 2010

One of the exciting things about mvc2 are Templated Helpers. Templated helpers allow you to create a template for any type – your own or a system type.

Let’s say we have a very simple model for a contact page.  Our model will be called ContactModel:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace EliteCodersLLC.com.Models
{
    public class ContactModel
    {
        [Required]
        public string Email { get; set; }

        public string Phone { get; set; }

        [Required]
        public string Inquiry { get; set; }

        [Required]
        public string Name { get; set; }
    }
}

We pulled in the DataAnnotations namespace so we could add some simple required validation for the class.  When we use the tooling built into Visual Studio to add a view by right-clicking in the controller action, we end up with a a view like so:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<EliteCodersLLC.com.Models.ContactModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Contact
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <div id="paper">
    <div>
        <h2>
            Contact</h2>
        <% using (Html.BeginForm())
           {%>
        <div class="editor-label">
            <%= Html.LabelFor(model => model.Email) %>
        </div>
        <div class="editor-field">
            <%= Html.TextBoxFor(model => model.Email) %>
            <%= Html.ValidationMessageFor(model => model.Email) %>
        </div>
        <div class="editor-label">
            <%= Html.LabelFor(model => model.Phone) %>
        </div>
        <div class="editor-field">
            <%= Html.TextBoxFor(model => model.Phone) %>
            <%= Html.ValidationMessageFor(model => model.Phone) %>
        </div>
        <div class="editor-label">
            <%= Html.LabelFor(model => model.Inquiry) %>
        </div>
        <div class="editor-field">
            <%= Html.TextAreaFor(model => model.Inquiry) %>
            <%= Html.ValidationMessageFor(model => model.Inquiry) %>
        </div>
        <p>
            <input type="submit" value="Submit" />
        </p>
        <% } %>
        <div>
            <%=Html.ActionLink("Back to List", "Index") %>
        </div>
        </div>
    </div>
</asp:Content>

However, what we can do is pull all the editor type stuff out and put it into a templated helper.  First thing we want to do is created a directory under Views/Shared called EditorTemplates. This will be where any shared editor templates will reside.  Of course, if you only want the template to be used for a particular set of views, put it in that folder.  For instance, if it should only be used from the Home controller and Views, you would create the EditorTemplates directory under Views/Home.

image

In there we want to create a partial, strongly typed view giving it the name of the type it will be the editor for.  In our case it will be for the ContactModel class, so it will be called ContactModel.ascx.

We’ll put all the editor markup in this new view.  This view can be customized in any way and will be used whenever Html.EditorForModel() is called when the Model is a ContactModel.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<EliteCodersLLC.com.Models.ContactModel>" %>
    <div class="editor-label">
        <%= Html.LabelFor(model => model.Email) %>
    </div>
    <div class="editor-field">
        <%= Html.TextBoxFor(model => model.Email) %>
        <%= Html.ValidationMessageFor(model => model.Email) %>
    </div>
    <div class="editor-label">
        <%= Html.LabelFor(model => model.Phone) %>
    </div>
    <div class="editor-field">
        <%= Html.TextBoxFor(model => model.Phone) %>
        <%= Html.ValidationMessageFor(model => model.Phone) %>
    </div>
    <div class="editor-label">
        <%= Html.LabelFor(model => model.Inquiry) %>
    </div>
    <div class="editor-field">
        <%= Html.TextAreaFor(model => model.Inquiry) %>
        <%= Html.ValidationMessageFor(model => model.Inquiry) %>
    </div>

And now our Home/Contact.aspx page simply has this inside the form:

        <% using (Html.BeginForm())
           {%>
        <%= Html.EditorForModel() %>
        <p>
            <input type="submit" value="Send" />
        </p>
        <% } %>

 

The same thing can be done for display templates as well. Do the same process but use DisplayTemplates as the folder name.

Happy coding!

Technorati Tags:
Wednesday, April 14, 2010 4:08:08 AM UTC  #    Comments [0] -
mvc
# Sunday, March 28, 2010

In the previous post we started talking about the Model. In this post we are going to add a little more substance to it.  The mason-dixon baseball site is mostly static, but there are a couple places that can benefit from the mvc model.  One in particular is the bat listing page.  This page lists the custom, hand-made bats that the company sells.

There are two listing sections, one for the most popular models which only lists the text and the full listing which shows the model number and an image:

image

There is also a listing for the wood staining:

image

And a listing of finished products and a description of the details of the finished bat:

image

So in looking at these listings, we can pull out the details of a model. 

    • Model #
    • Knob
    • Handle
    • Barrel
    • Unfinished Image
    • Finished Image
    • Popular

The listing of colors doesn’t fit into this model.  So for this exercise we are not going to focus on that.  We’ll concentrate on that when we discuss a ViewModel.

While this still is pretty static, it still qualifies for creating a model.

So, we’ll add both the BatModel and BatController classes and to keep the data easy, a bats.xml file.

image

Our Bats.xml file will be set like so:

<?xml version="1.0" encoding="utf-8" ?>
<Bats>
  <Bat>
    <ModelNumber></ModelNumber>
    <Knob></Knob>
    <Handle></Handle>
    <Barrel></Barrel>
    <UnfinishedImage></UnfinishedImage>
    <FinishedImage></FinishedImage>
    <Popular></Popular>
  </Bat>
</Bats>

 

Keeping our model nice and simple right now, it looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace mason_dixonbbaseball.com.Models
{
    public class BatModel
    {
        public string ModelNumber { get; set; }
        public string Knob { get; set; }
        public string Handle { get; set; }
        public string Barrel { get; set; }
        public string UnfinishedImage { get; set; }
        public string FinishedImage { get; set; }
        public bool Popular { get; set; }
    }
}

 

In the Controller class, we’ll use Reflection, so add:

using System.Reflection;

And we’ll be accessing the model:

using mason_dixonbbaseball.com.Models;

So our controller class will look like this:

using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Web.Mvc;

using mason_dixonbbaseball.com.Models;

namespace mason_dixonbbaseball.com.Controllers
{
    public class BatController : Controller
    {
        //
        // GET: /Bat/

        public ActionResult Index()
        {
            List<BatModel> bats = new List<BatModel>();

            // Get our type and pull out the public properties
            Type t = typeof(BatModel);
            PropertyInfo[] props = t.GetProperties(BindingFlags.Instance | BindingFlags.Public);

            // Pull the xml into a dataset
            DataSet ds = new DataSet();
            ds.ReadXml(this.ControllerContext.HttpContext.Request.MapPath("~/App_Data/Bats.xml"));

            // loop through the rows in the datatable and create BatModel instances
            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                BatModel bm = new BatModel();

                foreach (PropertyInfo prop in props)
                {
                    // set our properties setting empty values = null
                    prop.SetValue(bm, 
                        string.IsNullOrWhiteSpace(dr[prop.Name].ToString()) ? null 
                        : Convert.ChangeType(dr[prop.Name], prop.PropertyType), null);
                }

                bats.Add(bm);
            }

            return View(bats);
        }

    }
}

Next we’ll add a View.  Right click in the Index method and choose to Add View:

image

Simply running that with some beginning css changes that were made, we end up with this output:

image

Technorati Tags: ,
Sunday, March 28, 2010 7:43:14 PM UTC  #    Comments [0] -
.NET | mvc
# Thursday, March 18, 2010

We are going to do this in phases to simulate the progression that might happen over time.  This will also show some of the different ways to work with controllers and views.

The first way we are going to get data from the controller to the view is to put values directly into the ViewDataDictionary.  This is the least flexible and most fragile.  It’s the least flexible because the content (in this example) is compiled into the assembly.  The most fragile because the ViewDataDictionary is keyed by a string.  Mistype and the results will be wrong.

ViewData[“Message”] = “Hello world.”;

Misspell something and you’ve got to recompile the assembly.

ViewData[“Message”] = “Hello wolrd.”;

Rather than put all the content into one entry, you might be tempted to create a separate entry for each item:

ViewData[“Paragraph1”] … ViewData[“Paragraphx”]

Of course since ViewDataDictionary implements IDictionary<string, Object> (among other things), the value is an object, you can put whatever you want in there.  For instance:

ViewData["Message"] = new List<String>() { "Paragraph 1", "Paragraph 2" };

Then in the view cast it back out:

    <% foreach (var item in (List<String>)ViewData["Message"])
       {%>
         <div>
         <%: item %>
         </div>  
       <%} %>

 

Enter the model.  No, not Gisele Bündchen, the mvc model. 

            image        

Views have a Model property on them. This can be anything.  If you don’t use a strongly typed view, it still needs to be cast.  So, we can move the List into the return statement like so:

return View(new List<String>() { "Paragraph 1", "Paragraph 2" });

 

This will populate the Model property with our newly formed list.  Then we modify our view code like so:

    <% foreach (var item in (List<String>)Model)
       {%>
         <div>
         <%: item %>
         </div>  
       <%} %>

 

Still not ideal, but we are getting there.  System.Web.Mvc.ViewPage offers a generic version as well.  We’ll get into that next…

Technorati Tags: ,,
Thursday, March 18, 2010 1:42:43 AM UTC  #    Comments [0] -
.NET | mvc
# Thursday, March 04, 2010

So my company has been tasked with taking over Mason-Dixon Baseball's web site.  It’s currently all just static html pages with a little bit of css (obviously from a tool of some-sort with class names like style25) embedded in the pages.  Having gotten the owner’s approval, I’m turning this into a blog-series and moving the site to asp.net mvc2.

Like I said, it’s all static html right now and there’s not really much need for a database backend, but there are a couple spots that could use a little bit of data storage – primarily for the bats page.

We will be using Visual Studio 2010 RC and asp.net mvc RC2 or our work.

We are going to build this in phases.  First phase will be very basic.  Nothing really going on, we are going to concentrate on breaking the site down and building out basic views, controllers and centralizing css and images.

So, let’s get started! Open Visual Studio 2010 and File | New (or hit Ctrl-Shift-N).  We’ll call our project mason-dixonbaseball.com.

image

Click ok to create the unit test project as well.

The first thing we are going to do is modify our routing.  Since basically we just have static pages, we are going to add a new route.  The route that comes out of the box is this:

    routes.MapRoute(
        "Default",                                              // Route name
        "{controller}/{action}/{id}",                           // URL with parameters
        new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
    );

We want to keep this one around so we can utilize it later. So, we’ll change the name of that route and add a new one:
routes.MapRoute(
    "Default",
    "{action}",
    new { controller = "Home", action = "Index" }
    );

routes.MapRoute(
    "Id",                                              // Route name
    "{controller}/{action}/{id}",                           // URL with parameters
    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
);

 

This will allow us to have nicer urls like mason-dixonbaseball.com/bats.

In part 2, we’ll flesh out the controller.

Thursday, March 04, 2010 9:07:55 PM UTC  #    Comments [0] -
.NET | mvc
Archive
<February 2012>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2012
George Handlin
Sign In
Statistics
Total Posts: 51
This Year: 0
This Month: 0
This Week: 0
Comments: 9
All Content © 2012, George Handlin
DasBlog theme 'Business' created by Christoph De Baene (delarou)