Developing ASP.NET MVC 3 Application with EF CTP (Part 2)

First thing we want to do is create a controller for blog entries.  To do so, we will right-click on Controllers folder, select Add, then Controller.

image

On next screen we give it a name (BlogsController) and check the checkbox to create CRUD operations:

image

First method we are going to fill is Index method that will return the list of blog entries.  We will not use EF to return the list of blog posts sorted in ascending order by date.  We are not going to implement paging for now, we will come back to do this later.  Here is completed Index method(Index is just a naming convention)

        public ActionResult Index()
        {
           
using (BlogContext context = new BlogContext
())
            {
                context.Database.Connection.ConnectionString = 
                   
ConfigurationManager.ConnectionStrings["BlogsConnectionString"
].ConnectionString;
               
var blogs = (from one in
context.Entries
                            
orderby one.PostedOn descending
                             select
one).ToList();
               
return View(blogs);
            }
        }

 

As you can see the code is pretty simple.  Next step is to create index view. To do this right-click in the body of the method above and select Add View

image

Below you can see the options I selected.  We create strongly typed view based on BlogEntry class.  We use Razor (new in MVC 3.) engine and select list as view type.  Once we click Add, the IDE will scaffold the object and build the HTML view for us – Index.cshtml.  This new view will be added to Blogs folder.  Again we are using naming conventions to match controller and view

 

image

We are going to clean up the view by removing ID and text columns from the table.  We also update links to use appropriate ID from the object.  Here is final version of our view:

 

@model IEnumerable<MvcSampleApp.Models.BlogEntry>
 
@{
    View.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
    <h2>Index</h2>
 
    <p>
        @Html.ActionLink("Create New", "Create")
    </p>
 
    <table>
        <tr>
            <th></th>
            <th>
                Title
            </th>
            <th>
                PostedOn
            </th>
        </tr>
 
    @foreach (var item in Model) {
    
        <tr>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id=item.BlogEntryId }) |
                @Html.ActionLink("Details", "Details", new { id=item.BlogEntryId }) |
                @Html.ActionLink("Delete", "Delete", new { id=item.BlogEntryId })
            </td>
            <td>
                @item.Title
            </td>
            <td>
                @String.Format("{0:g}", item.PostedOn)
            </td>
        </tr>
    
    }
 
    </table>
 
 

 

To make this work, I had to update by Blog Entry class.  I had to add category ID in order to bind to it in the UI.  Question now is: looks like I need model objects on top of EF classes.  This seems counter-productive to me as I would have to duplicate properties.  I think the goal would be to use composition or inheritance to have model derive or expose EF class.  I will work on refactoring efforts right after the app is working.

    public class BlogEntry
    {
        [
Key
]
       
public int BlogEntryId { get; private set
; }
 
        [
Display(Name = "Title"
)]
        [
StringLength
(30, MinimumLength = 5)]
        [
Required
]
       
public string Title { get; set
; }
 
        [
Display(Name = "Post Text"
)]
        [
StringLength(int
.MaxValue)]
        [
Required
]
       
public string PostText { get; set
; }
 
        [
Display(Name = "Category"
)]
       
public virtual BlogCategory Category { get; set
; }
 
        [
Display(Name = "Post Date"
)]
        [
Range(typeof(DateTime), "1/1/1900", "12/31/2099"
)]
        [
Required
]
       
public DateTime? PostedOn { get; set
; }
 
       
public IEnumerable<BlogCategory> Categories { get; set
; }
 
        [
Required
]
        [
Display(Name = "Category"
)]
       
public int CategoryID { get; set; }
    }

 

In Razor syntax @ symbol indicates C# code, where < symbol indicates HTML tags.  As you can see on top we define model for the view, which in our case is the argument passed into the View in the Index method of the controller.  We also need to add a link to the menu for blog posts.  We add it to the _Layout.cshtml view:


                <ul id="menu">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                    <li>@Html.ActionLink("Blogs", "Index", "Blogs")</li>
                </ul>

 

Next step is to create new post view.  We also need to add code to Create method of the new view.  Here is how Create method looks:

        public ActionResult Create()
        {
           
return View(new BlogEntry());
        }

 

Now, same step as above – right-click, add view, select Create option from View Content drop down.  Then I will remove ID field.  Here is the end result of that.

@model MvcSampleApp.Models.BlogEntry
 
@{
    View.Title = "Create";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
<h2>Create</h2>
 
    @using (Html.BeginForm()) {
        @Html.ValidationSummary(true)
 
        <fieldset>
            <legend>Blog Post</legend>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.Title)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </div>
 
                          <div class="editor-label">
                @Html.LabelFor(model => model.Title)
            </div>
            <div class="editor-field">
                @Html.DropDownListFor(model=>model.CategoryID, new SelectList(Model.Categories, "CategoryId", "CategoryName", Model.CategoryID), "– Select Category –")
                @Html.ValidationMessageFor(model => model.Title)
            </div>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.PostText)
            </div>
            <div class="editor-field">
                @Html.TextAreaFor(model => model.PostText)
                @Html.ValidationMessageFor(model => model.PostText)
            </div>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.PostedOn)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.PostedOn)
                @Html.ValidationMessageFor(model => model.PostedOn)
            </div>
            <div>
                                   <input type="submit" value="Create" />
                          </div>
        </fieldset>
 
    }
 
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
 
 

Next step is to create controller method to save new blog post

        [HttpPost]
       
public ActionResult Create(BlogEntry
entry)
        {
 
           
try
            {
               
if
(entry.CategoryID > 0)
                {
                    entry.Category = GetCategory(entry.CategoryID);
                }
               
if
(TryValidateModel(entry))
                {
                   
using (BlogContext context = new BlogContext
())
                    {
                        context.Database.Connection.ConnectionString =
                   
ConfigurationManager.ConnectionStrings["BlogsConnectionString"
]
                    .ConnectionString;
                        context.Entries.Add(entry);
                        context.SaveChanges();
                    }
 
                   
return RedirectToAction("Index"
);
                }
               
else
                {
                    entry.Categories = GetCaregories();
                   
return
View(entry);
                }
            }
           
catch
            {
               
return View();
 
            }
        }

 

There are still parts of the method that can be optimized.  I will look at those once the application is completed.

In the next post I will look at the edit and delete methods.

2 Comments

  1. This is far and away the best article I have found on this subject and I have read many.
    It is clear, concise, complete and as Mark pointed out, very well presented.
    You have a talent. Thankyou.

Leave a Reply to Mark Cancel reply

Your email address will not be published. Required fields are marked *