Create and Edit Onetomany with Viewmodel

Asked

Viewed 1,323 times

2

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

I have a News class 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 am doing so:

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")
}

But when sending the form I get the following error: Edit: Complete 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

Códido Action Index

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

I really don’t know what’s going on.

  • How are you sending the POST to Create? Have you tried to insert the [Httppost] attribute into your Create(Newscategoriavm model)

  • The attribute is already inserted.

  • Put your view too.

  • Apparently we are looking in the wrong place. Stack Trace indicates '/', which is usually the route of the method Index from your controller. What’s in it?

  • Just take all the news you have in the bank and show in a table.

  • Right. Can you please post the code of this Index?

  • I posted the code!

Show 2 more comments

2 answers

2


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 on your view, do this:

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

Done that? See if it solves. If it does, I indicate with "certainty" the problem that was happening.

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

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

Replace it with something like that

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

Bind attribute, build your view in controller, it is implicit, but it is recommended to use explicit when working with a class that has other classes as in your case. Try this and give us a feedback please.

PS: Remembering that in bind, you should put the screen fields that reference the objects

  • I posted the full view

  • Go now @Hermesautran resolves

  • It worked man, thanks for the help!

  • I don’t know if you understand what happened, but come on, as I said, what the "problem" was. @Hermesautran You were asking to be assigned in the list that binded the dropdownlist whatever was selected in that list. Ai would have an error even as he would not be able to assign a different value type to the typed field.

  • I understood yes, I analyzed the code well and I realized where I was going wrong and why I was wrong. Thanks again.

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 also needs to have an empty constructor:

public class Noticia
{
    ...

    public Noticia() {}
}
  • I did, but it still makes the same mistake.

  • I edited it. Look now.

  • I did it the way you put it, but the mistake still persists!

  • Which statement exactly does the error occur in? Stack Trace should indicate a source of yours with the line. I only saw two objects that might not have a constructor.

  • I posted the complete error with the full description.

  • I expanded the response.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.