Archive for category MVC

MVC Razor Syntax – Web forms “Master Page” content area equivalent

In razor instead Web Forms ContentArea’s in Master Pages you have @sections within your _Layout.cshtml file. In the _layout file you have a declaration such as;

@RenderSection("JavaScript", required: false)

Then in your content pages;

@section JavaScript
{
   <script type="text/javascript" src="@Url.Content("/Scripts/SomeScript.js")" />;
   <script type="text/javascript" src="@Url.Content("/Scripts/AnotherScript.js")" />;
}

Source : http://stackoverflow.com/questions/4311783/asp-net-mvc-3-razor-include-js-file-in-head-tag

No Comments

MVC strongly typed view returns a null model on post back

I recently ran into a problem where a form I had built (using the view creation dialogue) would always return a null model on post back.  The code was pretty simple;

        //
        // GET: /StockAdjustment/CreateForPart/{PartId}
        //[RequireRequestValue("id")]
        [Authorize(Roles = "Administrator")]
        public ActionResult CreateForPart(Guid id)
        {
            StockAdjustment sa = new StockAdjustment() {
                Part = parts_repo.GetPart(id)
            };

            return View(sa);
        }

        //
        // POST: /StockAdjustment/CreateForPart/{PartId}
        [Authorize(Roles = "Administrator")]
        [HttpPost]
        public ActionResult CreateForPart(Guid id, StockAdjustment adjustment)
        {
            if (ModelState.IsValid)
            {
                adjustment.AddedBy = User.Identity.Name;
                adj_repo.Add(adjustment);
                adj_repo.Save();

                return RedirectToAction("Details", "Parts", new { Id = id });
            }
            else
            {
                adjustment.Part = parts_repo.GetPart(id);
                return View(adjustment);
            }
        }

The ModelState would always be invalid, despite the the fact that my data was all valid and fine. When I picked into the ModelState error using immediate mode I found the reported error;

ModelState.ToList()[0]
  {[id, System.Web.Mvc.ModelState]}
ModelState.ToList()[0].Value.Errors
  Count = 0
ModelState.ToList()[1].Value.Errors
Count = 1
    [0]: {System.Web.Mvc.ModelError}
ModelState.ToList()[1]
  {[adjustment, System.Web.Mvc.ModelState]}
ModelState.ToList()[1].Value.Errors[0]
{System.Web.Mvc.ModelError}
    ErrorMessage: ""
    Exception: {"The parameter conversion from type 'System.String' to type 
    'SimplyModel.Models.StockAdjustment' failed because no type converter can convert between these types."}

So model state contained the ID which had no errors, and adjustment which has this weird type conversion error. After a bit of hunting around my code I realised the problem- StockAdjustment has a field called adjustment which is an integer, however on my post back handler, i told MVC that my model instance should be called adjustment- so it looks like the MVC binder has got confused and figured the form field “adjustment” must represent the entire StockAdjustment model- i simply changed the method signature to accept the model with another name, and it all started to work;

        //
        // POST: /StockAdjustment/CreateForPart/{PartId}
        [Authorize(Roles = "Administrator")]
        [HttpPost]
        public ActionResult CreateForPart(Guid id, StockAdjustment a)
        {
            if (ModelState.IsValid)
            {
                a.AddedBy = User.Identity.Name;
                adj_repo.Add(a);
                adj_repo.Save();

                return RedirectToAction("Details", "Parts", new { Id = id });
            }
            else
            {
                a.Part = parts_repo.GetPart(id);
                return View(a);
            }
        }

9 Comments

MVC with MVVM using Knockout.js

Previously, on Shawson.co.uk..

see “Creating an Order/ Order Details style view using ASP.net MVC2 & Entity Framework 4″

So following on from my last MVC post I posed my question to Scott Hanselman himself via email, and he took the time to write me a very helpful response;

Interesting solution. Good job getting it working.
Take a look at maybe using some cleaner JS on the client…check out my last podcast on Knockout and check out this demo: http://knockoutjs.com/examples/contactsEditor.html
The pod cast he’s refering to is here.  The contacts editor example he pointed me to is exactly what I’m trying to do here.  This implementation would totally resolve my issue as you are no longer binding directly to the entity framework objects- I could instead create simple cut down DTO’s for the sale and it’s associated sale lines and serialise it to JSON then use Knockout (an open source javascript library which deals with clientside binding of UI elements to a data structure, like your ViewModel represented as JSON) to deal with all the client-side binding and editing before posting the data back as JSON.  I shall post again once I have something up and working.

6 Comments

ASP.net Roles and Membership installed to local SQL Express 2008 MDF file

Just had an hour or so’s worth of ball-ache from this issue!  Working on an MVC2 site, i wanted to move the default membership out of the aspnet mdf file and into the sites main MDF file.  This should be a pretty simple web.config change, and a matter of running aspnet_regsql against the database.  I read an article mentioning that you can do this straight from the command line to your MDF file, but I had no success with this method- it simply created another database for me with a name equal to the full path of the database i had requested.  So I found I had to attach my database to my local sqlexpress instance, then run it against that;  so in sql;


EXEC sp_attach_db 'mydb', N'E:\_Dev\5imply\5imply-MVC2\BackOffice\App_Data\5imply.mdf'

Then you can just run aspnet_regsql in the same way you would for any other database; In my example I just wanted Membership, roles and profiles

C:\Windows\Microsoft.NET\Framework\v2.0.50727>aspnet_regsql.exe -S .\SQLEXPRESS -d mydb -A mrp -E

Start adding the following features:
Membership
Profile
RoleManager

..

Finished.

C:\Windows\Microsoft.NET\Framework\v2.0.50727>

Then once you’re done, you can detach again;


exec sp_detach_db 'mydb'

Also- one other gotcha I found was that I had to do all this using SQL Management studio, having started it using “Run as Administrator”- I’m not sure if this is something specific to Windows 7, as  I would have expected to already be an administrator?  But I spent ages wondering why SQL refused to attach my database- Just kept getting an error “create file encountered operating system error 5″ I eventually ran procmon and found it just didn’t have permisisons to the file under the account it was running under.

1 Comment

Creating an Order/ Order Details style view using ASP.net MVC2 & Entity Framework 4

Before you start reading, beware!  I’m posting this because I’ve got a working solution, but I’m not convinced it’s the correct way to do this- I’m an MVC beginner myself so I’m hoping someone will post to either day “looks good” or say “this is ridiculous!” so don’t follow what i’ve written here as if it’s a tutorial!

I’ve just started my very first MVC2 project- it’s a pretty simple web based back office Warehouse/Order management system, tying into a frontend website. I boshed out a whole bunch of simple list/edit screens for Parts/ Couriers/ Stock movements etc saving the Order entry form till last as I couldn;t immidiatly imagine how this would work. What I wanted was the equivilant of an old school Access form with a sub form- like so;

edit_form

(Obviously, once everything’s working I will substitute the crazy GUID fields for some kind of swanky jQuery lookup!)

I started MVC following through Scott Hanselmans’ tutorials over on the Microsoft MVC site which shows building up a database, using Entity Framework 4 as an ORM, and extending those Model classes to set validation meta data- then building your simple controllers and a bunch of strongly typed views against these Entity Framework model classes (and some view models as required).

This all works fine when building one set of views per table- so I have a Parts database table, which I create a Parts controller for, then have a simple List, Create and Edit view which all works very well- the UpdateModel method happily updated my Model class from the form data on the strongly typed views.  It all becomes a little less clear though when you have a record which has a bunch of other associated records.  I need to not only Bind to a single records field, but also Bind to a List<> of associated records.

So I started googling and I found a bunch of links on google about binding to lists in MVC, including 3 quite pivotal ones all linked off of this StackOverFlow article;

There’s also an additional article off the back of one of those articles;

These links are all great and give good working examples of Binding to an object with a property which is a List<> of another object– but none of these are tied to any kind of data persistance which seems contrary to most of the MVC tutorials which show how easily you can write your controllers and view straight against the EF objects.  I can understand that in a full blown enterprise system you’re not going to be tying yourself straight to the EF classes anyway and you’de probably have a ViewModel or some kind of DTO which you pass between your data layer and your controllers- but I wanted to see this done with the EF objects, as I don’t think its something which should be difficult.

So I tried following the various methods but using my Entity Framework objects and had a whole world of problems.  Using Donn felker’s method I recieved this error;

“Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.”

I think I did eventually get past this error, but then I was hit by the same erorr I got using Steve Sanderson’s original method which was

“UpdateModel The EntityCollection has already been initialized. The InitializeRelatedCollection method should only be called to initialize a new EntityCollection during deserialization of an object graph”

This caused a Model error and stopped the form going through – I read various forum posts about removing this error from the ModelState error stack, but the save still failed.  I also experienced a bunch of other problems with the html field’s not being given the correct ID’s to map back to the models when using the HtmlPrefixScopeExtensions class that was part of the solution in the above articles. So I tried a whole bunch of variations of various articles I’d read and eventually gave up and decided to do something a bit different.

My Approach

In the model I have the entity model of my database, which gives me the Sale and SaleLine class- I create partial classes for these which hold the validation metadata.  I then created a ViewModel which will hold a single Sale and a List<SaleLine>, which are the lines which correspond to that sale.

If I bound the view straight to the Sale, then I would get SaleLines for free as a navigation item on the Sale class- i could dump the properties of the Sale to the form like normal, then just do a for loop going round Model.Salelines- when I post back then I have a single Sale object, with its attached records which can be automatically updated. But this seemed to be one of the issues I was having- when posting back, MVC was trying to rebuild my Sale object from the view data, which it did with no problems, but when it came to reattaching all the associated SaleLines, entity framework would start complaining that they already exist. So splitting them out in the ViewModel breaks the SaleLines out of the EntityCollection and just creates a generic List of SaleLines which I can itterate through using an index and then process manually on the post back.

// Model Partial Classes

[MetadataType(typeof(SaleMetadata))]
public partial class Sale
{
public Sale() {
this.Id = Guid.NewGuid();
this.CreateDate = DateTime.Now;
}
class SaleMetadata
{
// TODO
}
}

[MetadataType(typeof(SaleLineMetadata))]
public partial class SaleLine
{
class SaleLineMetadata {
[Required(ErrorMessage = "Please enter a quantity.")]
[Range(1,99999,ErrorMessage="Quantity must be at least 1!")]
public object Qty { get; set; }
}
}

// ViewModel

public class SaleViewModel
{
public Sale Sale { get; set; }
public List<SaleLine> SaleLines { get; set; }
}

On my SaleController’s Edit method, I setup the ViewModel and return it to the View.

public ActionResult Edit(Guid id)
{
SaleViewModel svm = new SaleViewModel()
{
Sale = db.Sales.Single(x => x.Id == id),
SaleLines = db.SaleLines.Where(x => x.SaleId == id).ToList()
};

return View(svm);
}

The View is a standard Edit view, with the for loop at the bottom to render out the Salelines;

<fieldset><legend>Items</legend>

<table id="rows">
<tr>
<th>Part Id</th>
<th>Qty</th>
<th>Sale Price</th>
<th>&nbsp;</th>
</tr>

<% for (int i = 0; i < Model.SaleLines.Count; i++ )
{ %>
<tr>
<td>
<%: Html.HiddenFor(model => model.SaleLines[i].Id) %>
<%: Html.TextBoxFor(model => model.SaleLines[i].PartId)%>
<%: Html.ValidationMessageFor(model => model.SaleLines[i].PartId)%>
</td>

<td>
<%: Html.TextBoxFor(model => model.SaleLines[i].Qty)%>
<%: Html.ValidationMessageFor(model => model.SaleLines[i].Qty)%>
</td>

<td>
<%: Html.TextBoxFor(model => model.SaleLines[i].SalePrice)%>
<%: Html.ValidationMessageFor(model => model.SaleLines[i].SalePrice)%>
</td>

<td>
<%= Html.ActionLink("Remove", "DeleteRow", new { id = Model.SaleLines[i].Id }, new { Class = "removeItem" })%>
</td>

</tr>
<% } %>

</table>

<a href="#" id="addItem">Add another...</a>

To Handle the post back I can update the Sale as normal, then I grab a list of the SaleLines from the database, and itterate through them manually updating each one;

[HttpPost]
public ActionResult Edit(Guid id, SaleViewModel svm)
{
if (ModelState.IsValid)
{
Sale s = db.Sales.Single(x => x.Id == id);
UpdateModel(s, "Sale");

List<SaleLine> db_lines = s.SaleLines.ToList();

for (int i = 0; i < svm.SaleLines.Count; i++)
{
SaleLine form_line = svm.SaleLines[i];
SaleLine db_line = db_lines.FirstOrDefault(x => x.Id == form_line.Id);

if (db_line == null)
{
//create a new one
form_line.Id = Guid.NewGuid();
form_line.SaleId = id;
db.AddToSaleLines(form_line);
//db.SaveChanges();
}
else
{
UpdateModel(db_line, "SaleLines[" + i + "]");
}
}

db.SaveChanges();

return RedirectToAction("Index");
}
else
{
return View(svm);
}
}

Adding an extra row, is all done entirly with jQuery– and this is one of the bits that doesn’t feel right.. I grabbed the html from an existing row, then modify it myself adjusting the ID’s so it’s a new row. When the View gets posted back, MVC is clever enough to be able to pick up my new row along with the others, and I have some logic to check if this row has a corresponding row in the SaleLines list, and if not, to create a new one.

var current_count = <%=Model.SaleLines.Count %>;

$("#addItem").click(function () {
$("#rows").append('<tr><td><input type="text" value="" name="SaleLines[' + current_count + '].PartId"></td><td><input type="text" value="" name="SaleLines[' + current_count + '].Qty" ></td><td><input type="text" value="" name="SaleLines[' + current_count + '].SalePrice"></td></tr>');
current_count++;
return false;
});

$("a.removeItem").live("click", function () {
remove_row = $(this).parent().parent()
$.ajax({
url: this.href,
cache: false,
success: function(html) { $(remove_row).remove(); reNumber(); }
});
return false;
});

function reNumber() {
var i = -1;
$("#rows tr").each(function (element_id, element) {
$("input[id$='Id']", $(element)).attr('id', 'SaleLines_' + i + '__Id').attr('name', 'SaleLines[' + i + '].Id');
$("input[id$='PartId']", $(element)).attr('id', 'SaleLines_' + i + '__PartId').attr('name', 'SaleLines[' + i + '].PartId');
$("input[id$='Qty']", $(element)).attr('id', 'SaleLines_' + i + '__Qty').attr('name', 'SaleLines[' + i + '].Qty');
$("input[id$='SalePrice']", $(element)).attr('id', 'SaleLines_' + i + '__SalePrice').attr('name', 'SaleLines[' + i + '].SalePrice');

i++;
});
}

The above javascript also has a bit of code to remove rows- this calls a method on the controller (DeleteRow- see below) and then removes the table row from the html.

// AJAX GET : /Sales/DeleteRow/{RowId}
public bool DeleteRow(Guid id)
{
try
{
SaleLine line = db.SaleLines.Single(x => x.Id == id);
db.SaleLines.DeleteObject(line);
db.SaveChanges();
return true;
}
catch (Exception)
{
return false;
}
}

This broke the update method though as the indexes were no longer sequencial- the html which gets spat out by MVC puts an index number against each row, and putting gap in this numbering stops the full collectino of items being passed, so I have to renumber the remaining items (the reNumber function shown in the javascript listing above). This feel’s like a total hack; I’ve read some articles about non-sequencial indexing, but I don’t have enough MVC XP’s to be able to apply this and the interweb is a bit thin on the ground for code examples which include the all important UpdateModel and persistance part of the code!

Anyway- comments would be appreciated! Is this a completly mental way of doing things? Have you read any other articles which implement differently?

12 Comments