Can't serialize an object - c#

I defined a model like this
public class Planilla
{
[Key]
public int IDPlanilla { get; set; }
[Required(ErrorMessage = "*")]
[Display(Name = "Dirección de Negocio")]
public int IDDireccionDeNegocio { get; set; }
[Required (ErrorMessage = "*")]
public string Nombre { get; set; }
[Display(Name = "Descripción")]
public string Descripcion { get; set; }
public bool Activo { get; set; }
[ScriptIgnore]
public virtual DireccionDeNegocio DireccionDeNegocio { get; set; }
}
And I have a method in my controller that returns the first element of this model
[HttpPost]
public ActionResult GetElements(string IDCampana)
{
Planilla query = db.Planillas.First();
return Json(query);
}
My problem is when I invoke this method from client side throws an error that say's
circular reference is detected trying to serialize
System.Data.Entity.DynamicProxies.Planilla_7F7D4D6D9AD7AEDCC59865F32D5D02B4023989FC7178D7698895D2CA59F26FEE
Debugging my code I realized that the object returned by the execution
of the methodFirstit's a
{System.Data.Entity.DynamicProxies.Planilla_7F7D4D6D9AD7AEDCC59865F32D5D02B4023989FC7178D7698895D2CA59F26FEE}
instead a Model of my namespace like
Example.Models.DireccionDeNegocio`.
Why am I doing wrong?? Because I tried with other models and work's well

Use view models, that's the only advice I can give you. Never pass domain models to your views. It's as simple as that. And if you respect this simple rule and fundamental rule in ASP.NET MVC applications you will never have problems. So for example if you need only the id and the description in your view:
[HttpPost]
public ActionResult GetElements(string IDCampana)
{
Planilla query = db.Planillas.First();
return Json(new
{
Id = query.IDPlanilla,
Description = query.Description
});
}
Notice that in this case the anonymous object serves as view model. But if you really wanted to do things properly you would write your view model:
public class PlanillaViewModel
{
public int Id { get; set; }
public string Description { get; set; }
}
and then:
[HttpPost]
public ActionResult GetElements(string IDCampana)
{
Planilla query = db.Planillas.First();
return Json(new PlanillaViewModel
{
Id = query.IDPlanilla,
Description = query.Description
});
}
By the way Ayende wrote a nice series of blog posts about this.

System.Data.Entity.DynamicProxies.* is the Entity Framework proxy namespace. Your DbContext creates your entities as such to support lazy loading and change tracking. This isn't your problem. The problem likely lies in a circular association.

Related

error 1061. T doesn't contain a definition for <propertyName>

i am having around 7 models who have same properties(atributes). On view page i am using a model(name = commonModel) which contains all those properties and a extra property to choose in which model's database i want to save that sent data so i created a valuesRelocate Method that will assign all the properties of commonModel to the choosen model (in this case article).
The code i gave below is working but i am getting a error when assigning value of a property of commonModel to a property of article.
What is the better way to do this.
Error is at tempModel.question
public ActionResult Create([Bind(Include =
"Id,question,ans,ruleApplicable,hint,exception,modelSelector")]
commonModel commonModel)
{
if (ModelState.IsValid)
{
if (commonModel.modelSelector == "article")
{
article model2 = new article();
article model1 = valuesRelocate<article>(commonModel,
model2);
db.articleDb.Add(model1);
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(commonModel);
}
private T valuesRelocate<T>(commonModel commonModel, T tempModel) {
tempModel.question = commonModel.question;
return tempModel;
}
I am using a abstract base class named baseGrammar .code for both the class is shown below
public abstract class baseGrammar
{
[Key]
public int Id { get; set; }
[Required]
public string question { get; set; }
[Required]
public string ans { get; set; }
public string ruleApplicable { get; set; }
public string hint { get; set; }
public bool exception { get; set; }
}
the one shown above is base class
and those shown below are derived classes
i use different classes because i wanted to have different classes for different grammatical concepts.
public class article : baseGrammar
{
}
public class commonModel : baseGrammar
{
[Required]
public string modelSelector { get; set; }
}
hope this helps.
You just need to constrain the type parameter T to be derived from your base class:
// Names changed to follow .NET naming conventions
private T RelocateValues<T>(BaseGrammar baseModel, T tempModel)
where T : BaseGrammar
{
tempModel.question = baseModel.question;
return tempModel;
}
However, given that you're modifying the incoming model, you could remove the return value and just change the method to:
private void RelocateValues(BaseGrammar from, BaseGrammar to)
{
to.question = from.question;
}
Then in your calling code:
Article model = new Article();
RelocateValues(model);
db.ArticleDb.Add(model);
There's no need to have two separate variables which will refer to the same object anyway...

Include only one property, not entire database row

Model:
public class Word
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime? WhenCreated { get; set; }
public ApplicationUser Author { get; set; }
[NotMapped]
public string AuthorName
{
get
{
if (Author != null)
{
return Author.UserName;
}
else {
return "";
}
}
}
public List<Definition> Definitions { get; set; }
}
Controller:
[HttpGet]
public IEnumerable<Word> Get()
{
return _db.Words.Include(x=>x.Author).ToList();
}
My Controller now returns entire ApplicationUser class which is one of properties of Word. I want to send only one property of ApplicationUser: UserName. How can I do that?
I've added AuthorName, which would return only data that I want from ApplicationUser. Unfortunately I still have to .Include(x=>x.Author) to make this property work. Can I somehow omit including Author in process of data serialization (to hide it when sending data to user)?
I know I can use .Select() method, but it requires me to type all properties I will need. If I modify my Model in the future, I will need to update all those .Select() which will would be inconvenient and waste of time.
How would you solve that?
You need to create a Dto object and assign the values to it and return the Dto instead.
Dto
public class WordDto
{
public string Title { get; set; }
public DateTime? WhenCreated { get; set; }
public string AuthorName { get; set; }
}
Then in your action
[HttpGet]
public async Task<IEnumerable<WordDto>> Get()
{
return _db.Words
.Include(x=>x.Author)
.Select(x =>
new WordDto
{
Title = x.Title,
DateTime = x.WhenCreated,
AuthorName = x.Author?.UserName ?? string.Empty
}
)
.ToListAsync();
}
You can try it as shown below.
Note : You don't need to use Include here.
[HttpGet]
public async Task<IEnumerable<Word>> Get()
{
return _db.Words.Select(x => new
{
Word = x,
AuthorName = x.Author.UserName
}
).ToList();
}
Create a View model and use AutoMapper to populate. Look at using AutoMapper and ProjectTo extension https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions
That way if you add properties to View model they will be automatically mapped if they exist on your EF model
So create a VM with required properties named appropriately (see AutoMapper docs on naming conventions):
public class WordVM
{
public string Title { get; set; }
public DateTime? WhenCreated { get; set; }
public string AuthorUserName { get; set; }
}
Then use AutoMapper to project (it will do any required includes so if you changed the VM later then it would handle that)
_db.Words.ProjectTo<WordVM>().ToList();
You don't need the NotMapped property AutoMapper would map the navigation property Author and the Author Property UserName to AuthorUserName
My workaround was to get all the related entities with .include(), then loop over them and omit the property values I did not want to return. It would require some maintenance in case your model changed, but surprisingly, it did not impact the response time dramatically.

MVC ViewModel, using a VM with some properies marked required, depending if its a GET or POST

I've often found myself fixing validations for the modelstate manually, due to the inconsistency of some fields that are required in a view model during post and get.
Supposing I've got this View Model:
public class RestaurantMenuName_ViewModel
{
public Int64 RestaurantMenuNameId { get; set; }
public Int64 OwnerId{ get; set; }
public string MenuNameCategory { get; set; }
public string CategoryDescription { get; set; }
public bool IsFormSaved { get; set; }
}
During a GET request the controller/Action requires the validation of just the fields, RestaurantMenuNameId and OwnerId. When calling the Action RestaurantMenuName, the query string values are RestaurantMenuNameId and OwnerId. Modelstate validation will be done on:
RestaurantMenuNameId
OwnerId
During a POST request the controller/Action will require the modelstate validation of the fields:
RestaurantMenuNameId
OwnerId
MenuNameCategory
CategoryDescription
This is the inconsistency issue I'm talking about, a solution could be using a ViewModel for Get requests and one for Post, but this could be real a time waster and error prone. Using ViewBag is out of discussion.
Question:
Is there a way to tell MVC that we want some fields [required] for GET and other for POST?
The following is a Pseudo-code of what I'm talking about:
public class RestaurantMenuName_ViewModel
{
[Required: in GET, POST] //<--Pseudo code
public Int64 RestaurantMenuNameId { get; set; }
[Required: in GET, POST] //<--Pseudo code
public Int64 OwnerId { get; set; }
[Required: in POST] //<--Pseudo code
public string MenuNameCategory { get; set; }
[Required: in POST] //<--Pseudo code
public string CategoryDescription { get; set; }
public bool IsFormSaved { get; set; }
}
It's not a very good practice (and confusing in your case) to pass complex objects when you need only few properties. It will be better to pass only the required ids as primitives.
If the case is special and you really need the complex objects, it will be better to create two different view models for every request and decorate the required properties accordingly.
However, you can create your own require validation attribute which will validate properties dependening on the current request.
public class MyRequiredAttribute : ValidationAttribute
{
private string httpVerb;
public MyRequiredAttribute(string httpVerb)
{
this.httpVerb = httpVerb;
}
public override bool IsValid(object value)
{
if(HttpContext.Current.Request.HttpMethod == this.httpVerb)
{
return value != null;
}
return true;
}
}
// Usage
public class MyViewModel
{
[MyRequired("GET")]
public string A { get; set; }
[MyRequired("POST")]
public string B { get; set; }
}
Note: you can use an enumeration to avoid some difficulties (ex. upper case, lower case, misspelling etc.) and also you can override the FormatErrorMessage method to change the default error message and format it properly.

Is there any way to pass a whole model via html.actionlink in ASP.NET MVC 3 razor

#Html.ActionLink("Reply", "BlogReplyCommentAdd", "Blog",
new { blogPostId = blogPostId, replyblogPostmodel = Model,
captchaValid = Model.AddNewComment.DisplayCaptcha },null)
My Controller :
public ActionResult BlogReplyCommentAdd(int blogPostId, BlogPostModel model, bool captchaValid)
{}
In my Controller i am passing whole model.But values of properties are null till reach to Action
BlogPostModel:
[Validator(typeof(BlogPostValidator))]
public partial class BlogPostModel : BaseNopEntityModel
{
public BlogPostModel()
{
Tags = new List<string>();
Comments = new List<BlogCommentModel>();
AddNewComment = new AddBlogCommentModel();
}
public string SeName { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public bool AllowComments { get; set; }
public int NumberOfComments { get; set; }
public DateTime CreatedOn { get; set; }
public IList<string> Tags { get; set; }
public IList<BlogCommentModel> Comments { get; set; }
public AddBlogCommentModel AddNewComment { get; set; }
}
Any how i need whole model.
Thanks in advance
You're not going about this correct way at all. The only time whole model data gets passed in the query string like this is when an HTML form is submitted via a GET operation; and even then that's not ideal except in cases where HTTP caching isn't a problem.
In this case, you're already passing the ID of the blog post in the query string to the controller method - so in your controller method you go and retrieve the blog post model and then pass it to the view.
Edit Upon adding this answer - #levelnis' comment then showed up - what (s)he's/they've said is exactly the same thing.
Update
And think about it - if you make it so that's how your site works - then anybody could 'publish' content on your blog's site by seeding the query string with all sorts of horrible stuff, not to mention making your site a playground for SEO spammers and such.

Is it possible to validate an MVC-3 model without validating "sub-models"?

I have a class that requires another class to be specified, but I don't want the MVC ModelState validator to check whether the secondary model is valid. Is this possible?
Here's a brief overview:
My entities look something like this:
public class WidgetType
{
public long Id { get; private set; }
[Required]
public string Name { get; set; }
...
}
public class Widget
{
public long Id { get; private set; }
[Required]
public string Name { get; set; }
[Required]
public WidgetType WidgetType { get; set; }
...
}
I have them encapsulated in a WidgetViewModel class that I'm passing to/from the View like this:
public class WidgetViewModel
{
public Widget Widget { get; set; }
public ICollection<WidgetType> WidgetTypes
{
get
{
return _repository.GetWidgets();
}
}
...
}
My view looks something like this:
...
#Html.DropDownListFor( m => m.Widget.WidgetType.Id, new SelectList( new EquipmentViewModel().EquipmentTypes, "Id", "Name" ) )
...
All of this works except for validation. ModelState.IsValid is always false because "Widget.WidgetType.Name" is required. I need the user to select a WidgetType, but I don't want ModelState to be validated deeper than "Widget.WidgetType.Id" (which should be all that Widget needs for its foreign key?).
Is there a better way to do this? I feel like there should be some way to validate without recursively inspecting deeper into the properties, but I can't find it. What am I missing...?
public class WidgetViewModel
{
[Required]
public string Name { get; set; }
[Required]
public WidgetType WidgetTypeId { get; set; }
public SelectList WidgetTypes
{
get
{
//This should be popuplated in your controller or factory not in the view model
retun new SelectList{ _repository.GetWidgets(),"Id","Name");
}
}
}
In your view
#Html.DropDownListFor( m => m.WidgetTypeId, Model.WidgetTypes)
And in your controller
public ActionResult Create(WidgetViewModel model)
{
Widget widget = new Widget{
Name = model.Name,
WidgetType = yourManager.GetWidgetTypeByID(model.WigetTypeId);
};
yourManager.Create(widget);
//...
}
If all you need in your view is the WidgetID then you don't need to include the entire Widget in the WidgetViewModel. Just have property called WidgetID. View model classes should have only the data the is necessary for the view.
In the controller action method that is called when you submit the form, you can use the WidgetID to fetch the Widget object from the database if it is needed.
http://blog.stevensanderson.com/2010/02/19/partial-validation-in-aspnet-mvc-2/ gives an example of partial validation

Categories

Resources