2

I will try to explain as best i can... Huge post coming as i'm not 100% where the problem lies. It probably has a really simple fix but i'm pulling hair at the min.

I have an abstract base class with a navigation property to a document type like so

public abstract class Document: Identity
{

    public int DocumentTypeId { get; set; } // this remains and alls good
    public virtual DocumentType DocumentType { get; set; } // this dissappears.
}

This DocumentType object contains a string value for the namespace for the type of object that it is. As an example I then have a class derived the document abstract class like so

public class Blog : Document
{
//properties excluded to keep this post from being HUGE!
}

They all have properties which are saving back to the database. however the document type is missing. Not the DocumentTypeId, that is there, but the actual DocumentType, I need to navigate into it to get the namespace value but it is missing.

It now gets a bit more complicated. I am using a ninject generic repository that injects, in this case the Blog into the view. Here is an example controller.

public class ContentController : Controller
{
    private IRepository<Document> repo;

    public ContentController(IRepository<Document> _repo)
    {
        repo = _repo;
    }

    public ActionResult Settings(string name) //name is unique!
    {
        Document d = repo.First(x => x.Name == name);
        return View(d); // all properties are present
    }

    [HttpPost]
    public ActionResult Settings([AbstractBind()] Document obj)
    {
        repo.Save(obj); // documenttype is missing documenttypeId is present.

        return View(obj);

        // this does not work but refresh does?!
        //Document d = repo.First(x => x.Name == obj.name);
        //return View(d);

    }
}

because the view is bound to an abstract class I am using the editor for model like so

@model Core.Entities.Documents.Abstract.Document
@{
    ViewBag.Title = "Index";
    Layout = "~/Areas/Admin/Views/Shared/_CMSContent.cshtml";
}
<h2>Settings - @Model.Name</h2>

@using (Html.BeginForm())
{
@Html.Hidden("Namespace", Model.DocumentType.Namespace);

@Html.ValidationSummary(true)
@Html.EditorForModel();
<div class="editor-label">&nbsp;</div>
<div class="editor-field">
    <input type="submit" value="Save" class="btn" />
</div>
<br class="clear" />
@Html.ActionLink("< Back to List", "Index")
}

Notice that i am adding a hidden field for the namespace contained within the view. Also notice that i am using a custom binding method to figure out what type is actually being edited, by going through the following method:

protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
    var type = Assembly.GetAssembly(typeof(Document)).GetType(bindingContext.ValueProvider.GetValue("Namespace").AttemptedValue);
    var model = Activator.CreateInstance(type);
    bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
    return model;
}

this figures out what type it is, (Blog). How do i get the DocumentType reference back into my model on the HTTP post?

I have tried adding a hidden field for the type like this @Html.HiddenFor(x => x.DocumentType); but it doesn't work.

I also tried going and getting it from the repository again after saving (commented out in the example) but no joy. If i refresh the page then the field is back again as Ninject and EF figures out that the Id is a foreign key that points to the DocumentType.

I could go and get the document type by the id that is in the "Document obj" and attach it back to the object before returing it to the view but i think that this would be terrible practise.

Any ideas?

Adween
  • 2,792
  • 2
  • 18
  • 20
  • If anyone needs more code or wants to ask me any questions please do, I'm still scratching my head trying to figure out how to make it work properly. – Adween Apr 03 '12 at 17:58
  • What is `DocumentType`? Include the code. – Ivan Zlatev Sep 14 '12 at 13:34
  • DocumentType does not matter, it could be anything. The issue is it does not get bound in the abstract binding method but the ID does. The only way I've managed to get around this issue is by retrieving the object again, in this case "DocumentType" from the database using the Id which is bound. Until I find a better way this is the only way I've got it to work. – Adween Oct 02 '12 at 14:43
  • When you post back, it is assuming the Model is what is being posted back. Instead of @Html.Hidden("Namespace", Model.DocumentType.Namespace); try: @Html.Hidden("DocumentType", Model.DocumentType); – Daniel Lorenz Oct 10 '12 at 15:54
  • "I have tried adding a hidden field for the type like this @Html.HiddenFor(x => x.DocumentType); but it doesn't work." already tried this as in the post. – Adween Oct 10 '12 at 21:54
  • I ran into this too but didn't need to get it working. I guess you need to check your custom binder. I assume you've seen. http://stackoverflow.com/questions/7222533/polymorphic-model-binding and http://stackoverflow.com/questions/6484972/viewmodel-with-listbaseclass-and-editor-templates/6485552#6485552 – lko May 29 '13 at 22:30
  • @lko yeah i've seen them, this is really old post now and have gone down the route of re-getting the related objects. i guess this kind of makes sense as the view is only aware of the object it is operating on. It would be overkill if it stored all the child navigation objects. Where would it even put them if it was possible? View state! lol... – Adween May 30 '13 at 18:38

0 Answers0