Create and Edit OneToMany with ViewModel

2

I'm creating a simple news application in ASP.NET MVC 4.

I have a News category and a Category.

I made a ViewModel

public class NoticiaCategoriaVM
{
    public Noticia Noticia { get; set; }
    public SelectList Categorias { get; set; }
    public HttpPostedFileBase UrlFotoCapa { get; set; }
}

In the Create controller I'm doing this:

public ActionResult Create()
{
     var model = new NoticiaCategoriaVM();
     model.Categorias = new SelectList(_ctx.Categorias.ToList(), "CategoriaId", "Nome", "SelectedValue");

     return View(model);
}

And the Post as follows:

public ActionResult Create(NoticiaCategoriaVM model)
{
}

View

@using App.Rdp.Models
@model NoticiaCategoriaVM

@{
    ViewBag.Title = "Create";
    Layout = "~/Areas/admin/Views/Shared/_LayoutAdmin.cshtml";
}

<h4 class="page-header">Cadastar Notícia</h4>

@using (Html.BeginForm("Create", "Noticia", FormMethod.Post, new { role = "form", enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <div class="form-group">
        <h4>
            @Html.LabelFor(model => model.Noticia.Titulo, new { @class = "control-label" })
        </h4>
        @Html.TextBoxFor(model => model.Noticia.Titulo, new { @class = "form-control input-lg" })
        @Html.ValidationMessageFor(model => model.Noticia.Titulo, null, new { @class = "help-block" })
    </div>

    <div class="form-group">
        <h4>
            @Html.LabelFor(model => model.Noticia.Chapeu, new { @class = "control-label" })
        </h4>
        @Html.TextBoxFor(model => model.Noticia.Chapeu, new { @class = "form-control input-lg" })
        @Html.ValidationMessageFor(model => model.Noticia.Chapeu, null, new { @class = "help-block" })
    </div>

    <div class="row">
        <div class="col-lg-4">
            <div class="form-group">
                <h4>@Html.LabelFor(model => model.Noticia.Categoria, new { @class = "control-label" })</h4>
                @Html.DropDownListFor(model => model.Categorias, Model.Categorias, "- Selecione uma Categoria -", new { @class = "form-control input-lg" })
                @Html.ValidationMessageFor(model => model.Noticia.Categoria, null, new { @class = "help-block" })
            </div>
        </div>
        <div class="col-lg-4">
            <div class="form-group">
                <h4>@Html.LabelFor(model => model.Noticia.DataPostagem, new { @class = "control-label" })</h4>
                @Html.TextBoxFor(model => model.Noticia.DataPostagem, new { @class = "form-control input-lg" })
                @Html.ValidationMessageFor(model => model.Noticia.DataPostagem, null, new { @class = "help-block" })
            </div>
        </div>
    </div>

    <div class="checkbox" style="display: block; margin-bottom: 20px">
        <h4>
            @Html.EditorFor(model => model.Noticia.Destaque) Destaque
        </h4>
    </div>

    <div class="form-group">
        <h4>@Html.LabelFor(model => model.Noticia.UrlFotoCapa, new { @class = "control-label" })</h4>
        <div class="fileinput fileinput-new" data-provides="fileinput">
            <div class="input-group">
                <div class="form-control uneditable-input" data-trigger="fileinput">
                    <i class="glyphicon glyphicon-file fileinput-exists"></i>
                    <span class="fileinput-filename"></span>
                </div>
                <span class="input-group-addon btn btn-default btn-file">
                    <span class="fileinput-new">Select file</span>
                    <span class="fileinput-exists">Change</span>
                    @Html.TextBoxFor(model => model.UrlFotoCapa, new { type = "file", accept = "image/x-png, image/jpeg", @class = "input-lg" })
                </span>
                <a href="#" class="input-group-addon btn btn-default fileinput-exists" data-dismiss="fileinput">Remove</a>
            </div>
            @{
                if (ViewBag.Imagem != null)
                {
                    @ViewBag.Imagem
                }
            }
        </div>
    </div>

    <div class="form-group">
        <h4>@Html.LabelFor(model => model.Noticia.Conteudo, new { @class = "control-label" })</h4>
        @Html.TextAreaFor(model => model.Noticia.Conteudo, new { @class = "form-control input-lg" })
        @Html.ValidationMessageFor(model => model.Noticia.Conteudo, null, new { @class = "help-block" })
    </div>

    <hr />

    <p class="pull-right">
        <input type="submit" class="btn btn-primary" value="Cadastrar Notícia" />
    </p>
}
<div>
    @Html.ActionLink("Voltar Para Lista", "Index")
</div>

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

However when I submit the form I get the following error: Edit: Full error

Erro de Servidor no Aplicativo '/'.

Nenhum construtor sem parâmetros foi definido para este objeto.

Descrição: Ocorreu uma exceção sem tratamento durante a execução da atual solicitação da Web. Examine o rastreamento de pilha para obter mais informações sobre o erro e onde foi originado no código. 

Detalhes da Exceção: System.MissingMethodException: Nenhum construtor sem parâmetros foi definido para este objeto.

Erro de Origem: 

Exceção sem tratamento foi gerada durante a execução da atual solicitação da Web. As informações relacionadas à origem e ao local da exceção podem ser identificadas usando-se o rastreamento de pilha de exceção abaixo.

Rastreamento de Pilha: 


[MissingMethodException: Nenhum construtor sem parâmetros foi definido para este objeto.]
   System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
   System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +113
   System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +232
   System.Activator.CreateInstance(Type type, Boolean nonPublic) +83
   System.Activator.CreateInstance(Type type) +6
   System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +197

[MissingMethodException: Nenhum construtor sem parâmetros foi definido para este objeto. Tipo de objeto 'System.Web.Mvc.SelectList'.]
   System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +233
   System.Web.Mvc.DefaultModelBinder.BindSimpleModel(ControllerContext controllerContext, ModelBindingContext bindingContext, ValueProviderResult valueProviderResult) +284
   System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +281
   System.Web.Mvc.DefaultModelBinder.GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) +17
   System.Web.Mvc.DefaultModelBinder.BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) +382
   System.Web.Mvc.DefaultModelBinder.BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext) +101
   System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model) +55
   System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +1198
   System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +330
   System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +331
   System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +105
   System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__19(AsyncCallback asyncCallback, Object asyncState) +743
   System.Web.Mvc.Async.WrappedAsyncResult'1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +14
   System.Web.Mvc.Async.WrappedAsyncResultBase'1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
   System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +343
   System.Web.Mvc.Controller.<BeginExecuteCore>b__1c(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState) +25
   System.Web.Mvc.Async.WrappedAsyncVoid'1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +30
   System.Web.Mvc.Async.WrappedAsyncResultBase'1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
   System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +465
   System.Web.Mvc.Controller.<BeginExecute>b__14(AsyncCallback asyncCallback, Object callbackState, Controller controller) +18
   System.Web.Mvc.Async.WrappedAsyncVoid'1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +20
   System.Web.Mvc.Async.WrappedAsyncResultBase'1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
   System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +374
   System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +16
   System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState) +52
   System.Web.Mvc.Async.WrappedAsyncVoid'1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +30
   System.Web.Mvc.Async.WrappedAsyncResultBase'1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +384
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +48
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

EDIT

Coded Action Index

public ActionResult Index()
        {
            var noticias = _ctx.Noticias.ToList().OrderByDescending(n => n.NoticiaId);
            return View(noticias);
        }

I really do not know what's going on.

    
asked by anonymous 07.03.2014 / 20:44

2 answers

1

Try to do the following, create another attribute in your ViewModel to receive the category that is selected, for example

public class NoticiaCategoriaVM
{
    public Noticia Noticia { get; set; }
    public SelectList Categorias { get; set; }
    public HttpPostedFileBase UrlFotoCapa { get; set; }
    public string CategoriaSelecionada { get; set; }
}

And then in your view, do this:

@Html.DropDownListFor(model => model.CategoriaSelecionada, Model.Categorias, "- Selecione uma Categoria -", new { @class = "form-control input-lg" })

Done that? See if you can. If it does, I point out with certainty the problem that was happening.

  

It would be nice if you could post your view too, but try   do so

 public ActionResult Create(NoticiaCategoriaVM model) {   
//TODO: Seu método } 
     

Replace with something like this

 [HttpPost] public ActionResult
Create([Bind(Include="Noticia.Id,Noticia.Titulo")] NoticiaCategoriaVM
model)  {    //TODO: Seu método } 
     

The Bind attribute constructs its view in the controller, it is implicit,   but it is recommended to use explicitly when working with a class that   have other classes as in your case. Try this and give us a   feedback please.

     

PS: Remembering that in bind, you should put the fields on the screen that   refer to objects

    
07.03.2014 / 21:16
0

As you are using the news fields within the View, the object within the ViewModel needs to be initialized:

public class NoticiaCategoriaVM
{
    public Noticia Noticia { get; set; }
    public SelectList Categorias { get; set; }
    public HttpPostedFileBase UrlFotoCapa { get; set; }

    public NoticiaCategoriaVM() {
        Noticia = new Noticia();
    }
}

The class Noticia must also have an empty constructor:

public class Noticia
{
    ...

    public Noticia() {}
}
    
07.03.2014 / 20:46