Doug.Instance

Improving the world one post at a time
posts - 22 , comments - 46 , trackbacks - 0

Streetlight Store - Part III: Implementation in an MVC 4 Application

To keep things simple, I am going to retain the default security framework created by Visual Studio when I created the application.  However, I am going to change the database name to something more meaningful.  So in web.config, I am changing the connection string to this:

<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=StreetlightStoreSample;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\StreetlightStoreSample.mdf" providerName="System.Data.SqlClient" />

Next we’ll add the connection string from our database project found in Streetlight.Store.DataAccess\app.config:

<add name="StoreEntities" connectionString="metadata=res://*/DataModels.StoreDataModel.csdl|res://*/DataModels.StoreDataModel.ssdl|res://*/DataModels.StoreDataModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.\SQLEXPRESS;initial catalog=SAMPLE_STORE;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

Now let’s look at the home page which is the Views\Home\Index.cshtml view.  Most of the changes are cosmetic until we get to the lists at the bottom of the page.  Here we will link to some actions to be added to the MVC application:

<ol class="round">
    <li class="one">
        <h5>Store Management</h5>
        Manage your store by creating products and handling customer orders.
        @Html.ActionLink("Manage store…", "Index", "Admin")
    </li>

    <li class="two">
        <h5>Browse Products</h5>
        Customers hopefully want to buy your products so let's
        @Html.ActionLink("browse products…", "Index", "Products")
    </li>

    <li class="three">
        <h5>User Customization</h5>
        @if (Request.IsAuthenticated)
        {
            <text>Hey! You registered!  Now you can look at your past orders and
            manage your account information.</text>
        }
        else
        {
            <text>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" }) or
            @Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })
            to view past orders and manage your account information.</text>
        }
    </li>
</ol>

 

Next we will change the header menu found in \Views\Shared\_Layout.cshtml:

<nav>
    <ul id="menu">
        <li>@Html.ActionLink("Home", "Index", "Home")</li>
        <li>@Html.ActionLink("Admin", "Index", "Admin")</li>
        <li>@Html.ActionLink("Shop", "Index", "Store")</li>
    </ul>
</nav>

 

As a result, our new home page looks like this:

image

Note that this also required a change to Controllers\HomeController.cs controller class to change the message displayed by the Index action.

The Products Controller

Let’s create a ProductsController controller class to call the methods we created in Part II to manage products.  The first code we need to add to this class is the code to handle creation and disposal of the transaction manager:

public ITransactionManager TransactionManager { get; private set; }

public ProductsController()
{
    TransactionManager = new Streetlight.Store.DataAccess.DataManager();
}

protected override void Dispose(bool disposing)
{
    if (disposing && TransactionManager != null)
    {
        TransactionManager.Dispose();
    }

    base.Dispose(disposing);
}

 

Note that in this case we create a strongly-typed instance of the specific implementation of ITransactionManager (Streetlight.Store.DataAccess.DataManager) introduced in Part II.  In future posts, we will look at further abstracting the initialization of the TransactionManager property.

Next we will create the get and post actions to create a new product:

public ActionResult Create()
{
    Product model = new Product();

    return View(model);
}

[HttpPost]
public ActionResult Create(Product model)
{
    if (TransactionManager.Products.DuplicateItemNumberExists(string.Empty, model.ItemNumber))
    {
        ModelState.AddModelError("ItemNumber", "A product already exists with this item number.");
    }

    if (TransactionManager.Products.DuplicateGlobalIdManufacturerExists(string.Empty, model.GlobalId, model.Manufacturer))
    {
        ModelState.AddModelError("GlobalId", "A product already exists with this Global ID/Manufacturer combination.");
    }

    if (ModelState.IsValid)
    {
        TransactionManager.Products.CreateNew(model);

        return RedirectToAction("Edit", new { id = model.Id });
    }
    else
    {
        return View(model);
    }
}

 

To create the view to create a new product, we will use the default scaffolding in Visual Studio:

image

For now we will remove the status field and change the title so the final view looks like this in Views\Products\Create.cshtml:

@model Streetlight.Store.Contracts.Product

@{
    ViewBag.Title = "New Product";
}

<h2>New Product</h2>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Product</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.PackagingTypeCode)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.PackagingTypeCode)
            @Html.ValidationMessageFor(model => model.PackagingTypeCode)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.GlobalId)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.GlobalId)
            @Html.ValidationMessageFor(model => model.GlobalId)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Manufacturer)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Manufacturer)
            @Html.ValidationMessageFor(model => model.Manufacturer)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.PartNumber)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.PartNumber)
            @Html.ValidationMessageFor(model => model.PartNumber)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Weight)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Weight)
            @Html.ValidationMessageFor(model => model.Weight)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Description)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Description)
            @Html.ValidationMessageFor(model => model.Description)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ItemNumber)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ItemNumber)
            @Html.ValidationMessageFor(model => model.ItemNumber)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Length)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Length)
            @Html.ValidationMessageFor(model => model.Length)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Width)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Width)
            @Html.ValidationMessageFor(model => model.Width)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Height)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Height)
            @Html.ValidationMessageFor(model => model.Height)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

We can then create the List and Edit actions and view using the default scaffolding as well with more minimal changes.

Download the full source code from CodePlex.

Print | posted on Wednesday, March 6, 2013 6:42 PM |

Feedback

Gravatar

# re: Streetlight Store - Part III: Implementation in an MVC 4 Application

Doug- Great post! Codeplex says "THIS PROJECT IS NOT YET PUBLISHED". Also your screenshot images above are returning 404.
3/7/2013 10:16 AM | Travis
Gravatar

# re: Streetlight Store - Part III: Implementation in an MVC 4 Application

CodePlex project has been published. Sorry about that.
3/7/2013 10:21 AM | Doug
Post A Comment
Title:
Name:
Email:
Comment:
Verification:
 
 

Powered by: