I have the following entity models:
public class AssetLabel
{
public string QRCode { get; set; }
public string asset { get; set; }
public virtual IEnumerable<Conversation> Conversations { get; set; }
}
public class Conversation
{
public int ID { get; set; }
public virtual AssetLabel AssetLabel{ get; set; }
public string FinderName { get; set; }
public string FinderMobile { get; set; }
public string FinderEmail { get; set; }
public ConversationStatus Status{ get; set; }
public IEnumerable<ConversationMessage> Messages { get; set; }
}
public class ConversationMessage
{
public int ID { get; set; }
public DateTime MessageDateTime { get; set; }
public bool IsFinderMessage { get; set; }
public virtual Conversation Conversation { get; set; }
}
public enum ConversationStatus { open, closed };
public class FinderViewModel : Conversation
{/*used in Controllers->Found*/
}
My MVC application will prompt for a QRCode
on a POST request. I then validate this code exists in the database AssetLabel
and some other server-side logic is satisfied. I then need to request the user contact details to create a new Conversation
record.
Currently I have a GET to a controller action which returns the first form to capture the Code. If this is valid then I create a new FinderViewModel
, populate the AssetLabel
with the object for the QRCode
and return a view to consume the vm and show the fields for the Name
, Mobile
and Email
.
My problem is that although the AssetLabel
is being passed to the view as part of the FinderViewModel
and I can display fields from the AssetLabel
; graphed object the AssetLabel
does not get passed back in the POST. I know I could modify the FinderViewModel
so that it takes the Conversation
as one property and set up the QRCode
as a separate property that could be a hidden field in the form and then re-find the the AssetLabel
as part of the processing of the second form but this feels like a lot of work seeing as I have already validated it once to get to the point of creating the second form (this is why I am moving away from PHP MVC frameworks).
The first question is HOW?, The second question is am I approaching this design pattern in the wrong way. Is there a more .NETty way to persist the data through multiple forms? At this point in my learning I don't really want to store the information in a cookie or use ajax.
For reference the rest of the code for the 1st form POST, 2nd view and 2nd form POST are shown below (simplified to eliminate irrelevant logic).
public class FoundController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: Found
public ActionResult Index()
{
AssetLabel lbl = new AssetLabel();
return View(lbl);
}
[HttpPost]
public ActionResult Index(string QRCode)
{
if (QRCode=="")
{
return Content("no value entered");
}
else
{
/*check to see if code is in database*/
AssetLabel lbl = db.AssetLables.FirstOrDefault(q =>q.QRCode==QRCode);
if (lbl != null)
{
var vm = new FinderViewModel();
vm.AssetLabel = lbl;
vm.Status = ConversationStatus.open;
return View("FinderDetails", vm);
}
else
{/*Label ID is not in the database*/
return Content("Label Not Found");
}
}
}
[HttpPost]
public ActionResult ProcessFinder(FinderViewModel vm)
{
/*
THIS IS WHERE I AM STUCK! - vm.AssetLabel == NULL even though it
was passed to the view with a fully populated object
*/
return Content(vm.AssetLabel.QRCode.ToString());
//return Content("Finder Details posted!");
}
FinderView.cshtml
@model GMSB.ViewModels.FinderViewModel
@{
ViewBag.Title = "TEST FINDER";
}
<h2>FinderDetails</h2>
@using (Html.BeginForm("ProcessFinder","Found",FormMethod.Post))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Finder Details</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.ID)
@Html.HiddenFor(model => model.AssetLabel)
<div class="form-group">
@Html.LabelFor(model => model.FinderName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.FinderName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.FinderName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.FinderMobile, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.FinderMobile, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.FinderMobile, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.FinderEmail, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.FinderEmail, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.FinderEmail, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
Rendered HTML snippet for AssetLabel
<input id="AssetLabel" name="AssetLabel" type="hidden"
value="System.Data.Entity.DynamicProxies.AssetLabel_32653C4084FF0CBCFDBE520EA1FC5FE4F22B6D9CD6D5A87E7F1B7A198A59DBB3"
/>