Simple getter logic in ViewModels - asp.net-mvc

Is it ok to have simple logic (without any dependencies) in ViewModels getters or it should contain just automatic properties? in this case just checking for null so I don't have to do that in controller each time I am using this ViewModel. TicketSearchParameters is a simple model containing string and date properties, there is no Repository or any other dependencies.
public class MyViewModel
{
private TicketSearchParameters _searchParams;
public TicketSearchParameters SearchParams
{
get
{
if (_searchParams == null)
{
_searchParams = new TicketSearchParameters();
_searchParams.CreatedFrom = DateTime.Now.AddDays(-7);
_searchParams.CreatedTo = DateTime.Now;
}
return _searchParams;
}
set
{
_searchParams = value;
}
}
/*** other properties ***/
}

You code is fairly ok. But you can use NULL Object Design Pattern to check null and create NullObject.
make a class named NullSearchParams inherited from SearchParams and initialize it when needed.
You can see Null design pattern documentation here.
https://sourcemaking.com/design_patterns/null_object

Related

MVC Full Calendar Error [duplicate]

I am trying to do a simple JSON return but I am having issues I have the following below.
public JsonResult GetEventData()
{
var data = Event.Find(x => x.ID != 0);
return Json(data);
}
I get a HTTP 500 with the exception as shown in the title of this question. I also tried
var data = Event.All().ToList()
That gave the same problem.
Is this a bug or my implementation?
It seems that there are circular references in your object hierarchy which is not supported by the JSON serializer. Do you need all the columns? You could pick up only the properties you need in the view:
return Json(new
{
PropertyINeed1 = data.PropertyINeed1,
PropertyINeed2 = data.PropertyINeed2
});
This will make your JSON object lighter and easier to understand. If you have many properties, AutoMapper could be used to automatically map between DTO objects and View objects.
I had the same problem and solved by using Newtonsoft.Json;
var list = JsonConvert.SerializeObject(model,
Formatting.None,
new JsonSerializerSettings() {
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});
return Content(list, "application/json");
This actually happens because the complex objects are what makes the resulting json object fails.
And it fails because when the object is mapped it maps the children, which maps their parents, making a circular reference to occur. Json would take infinite time to serialize it, so it prevents the problem with the exception.
Entity Framework mapping also produces the same behavior, and the solution is to discard all unwanted properties.
Just expliciting the final answer, the whole code would be:
public JsonResult getJson()
{
DataContext db = new DataContext ();
return this.Json(
new {
Result = (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
}
, JsonRequestBehavior.AllowGet
);
}
It could also be the following in case you don't want the objects inside a Result property:
public JsonResult getJson()
{
DataContext db = new DataContext ();
return this.Json(
(from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
, JsonRequestBehavior.AllowGet
);
}
To sum things up, there are 4 solutions to this:
Solution 1: turn off ProxyCreation for the DBContext and restore it in the end.
private DBEntities db = new DBEntities();//dbcontext
public ActionResult Index()
{
bool proxyCreation = db.Configuration.ProxyCreationEnabled;
try
{
//set ProxyCreation to false
db.Configuration.ProxyCreationEnabled = false;
var data = db.Products.ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
finally
{
//restore ProxyCreation to its original state
db.Configuration.ProxyCreationEnabled = proxyCreation;
}
}
Solution 2: Using JsonConvert by Setting ReferenceLoopHandling to ignore on the serializer settings.
//using using Newtonsoft.Json;
private DBEntities db = new DBEntities();//dbcontext
public ActionResult Index()
{
try
{
var data = db.Products.ToList();
JsonSerializerSettings jss = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
var result = JsonConvert.SerializeObject(data, Formatting.Indented, jss);
return Json(result, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
}
Following two solutions are the same, but using a model is better because it's strong typed.
Solution 3: return a Model which includes the needed properties only.
private DBEntities db = new DBEntities();//dbcontext
public class ProductModel
{
public int Product_ID { get; set;}
public string Product_Name { get; set;}
public double Product_Price { get; set;}
}
public ActionResult Index()
{
try
{
var data = db.Products.Select(p => new ProductModel
{
Product_ID = p.Product_ID,
Product_Name = p.Product_Name,
Product_Price = p.Product_Price
}).ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
}
Solution 4: return a new dynamic object which includes the needed properties only.
private DBEntities db = new DBEntities();//dbcontext
public ActionResult Index()
{
try
{
var data = db.Products.Select(p => new
{
Product_ID = p.Product_ID,
Product_Name = p.Product_Name,
Product_Price = p.Product_Price
}).ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
}
JSON, like xml and various other formats, is a tree-based serialization format. It won't love you if you have circular references in your objects, as the "tree" would be:
root B => child A => parent B => child A => parent B => ...
There are often ways of disabling navigation along a certain path; for example, with XmlSerializer you might mark the parent property as XmlIgnore. I don't know if this is possible with the json serializer in question, nor whether DatabaseColumn has suitable markers (very unlikely, as it would need to reference every serialization API)
add [JsonIgnore] to virtuals properties in your model.
Using Newtonsoft.Json: In your Global.asax Application_Start method add this line:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
Its because of the new DbContext T4 template that is used for generating the EntityFramework entities. In order to be able to perform the change tracking, this templates uses the Proxy pattern, by wrapping your nice POCOs with them. This then causes the issues when serializing with the JavaScriptSerializer.
So then the 2 solutions are:
Either you just serialize and return the properties you need on the client
You may switch off the automatic generation of proxies by setting it on the context's configuration
context.Configuration.ProxyCreationEnabled = false;
Very well explained in the below article.
http://juristr.com/blog/2011/08/javascriptserializer-circular-reference/
Provided answers are good, but I think they can be improved by adding an "architectural" perspective.
Investigation
MVC's Controller.Json function is doing the job, but it is very poor at providing a relevant error in this case. By using Newtonsoft.Json.JsonConvert.SerializeObject, the error specifies exactly what is the property that is triggering the circular reference. This is particularly useful when serializing more complex object hierarchies.
Proper architecture
One should never try to serialize data models (e.g. EF models), as ORM's navigation properties is the road to perdition when it comes to serialization. Data flow should be the following:
Database -> data models -> service models -> JSON string
Service models can be obtained from data models using auto mappers (e.g. Automapper). While this does not guarantee lack of circular references, proper design should do it: service models should contain exactly what the service consumer requires (i.e. the properties).
In those rare cases, when the client requests a hierarchy involving the same object type on different levels, the service can create a linear structure with parent->child relationship (using just identifiers, not references).
Modern applications tend to avoid loading complex data structures at once and service models should be slim. E.g.:
access an event - only header data (identifier, name, date etc.) is loaded -> service model (JSON) containing only header data
managed attendees list - access a popup and lazy load the list -> service model (JSON) containing only the list of attendees
Avoid converting the table object directly. If relations are set between other tables, it might throw this error.
Rather, you can create a model class, assign values to the class object and then serialize it.
I'm Using the fix, Because Using Knockout in MVC5 views.
On action
return Json(ModelHelper.GetJsonModel<Core_User>(viewModel));
function
public static TEntity GetJsonModel<TEntity>(TEntity Entity) where TEntity : class
{
TEntity Entity_ = Activator.CreateInstance(typeof(TEntity)) as TEntity;
foreach (var item in Entity.GetType().GetProperties())
{
if (item.PropertyType.ToString().IndexOf("Generic.ICollection") == -1 && item.PropertyType.ToString().IndexOf("SaymenCore.DAL.") == -1)
item.SetValue(Entity_, Entity.GetPropValue(item.Name));
}
return Entity_;
}
You can notice the properties that cause the circular reference. Then you can do something like:
private Object DeCircular(Object object)
{
// Set properties that cause the circular reference to null
return object
}
//first: Create a class as your view model
public class EventViewModel
{
public int Id{get;set}
public string Property1{get;set;}
public string Property2{get;set;}
}
//then from your method
[HttpGet]
public async Task<ActionResult> GetEvent()
{
var events = await db.Event.Find(x => x.ID != 0);
List<EventViewModel> model = events.Select(event => new EventViewModel(){
Id = event.Id,
Property1 = event.Property1,
Property1 = event.Property2
}).ToList();
return Json(new{ data = model }, JsonRequestBehavior.AllowGet);
}
An easier alternative to solve this problem is to return an string, and format that string to json with JavaScriptSerializer.
public string GetEntityInJson()
{
JavaScriptSerializer j = new JavaScriptSerializer();
var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
return j.Serialize(entityList );
}
It is important the "Select" part, which choose the properties you want in your view. Some object have a reference for the parent. If you do not choose the attributes, the circular reference may appear, if you just take the tables as a whole.
Do not do this:
public string GetEntityInJson()
{
JavaScriptSerializer j = new JavaScriptSerializer();
var entityList = dataContext.Entitites.toList();
return j.Serialize(entityList );
}
Do this instead if you don't want the whole table:
public string GetEntityInJson()
{
JavaScriptSerializer j = new JavaScriptSerializer();
var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
return j.Serialize(entityList );
}
This helps render a view with less data, just with the attributes you need, and makes your web run faster.

ASP MVC 4 Using a class to validate a get/set within a model

working on a project right now and I'm relatively new to MVC, I have a model which looks something like
public class MyViewModel
{
public string check1 {get;set;}
public string check2 {get;set;}
}
I also have a class which I want to use to validate these checks using a custom regex, such as
public class WebCommon
{
public static bool Validation(string validate)
{
bool validatestatus = false;
Regex check = new Regex(my regex here);
if (check.IsMatch(validate))
{
validatestatus = true;
return validatestatus;
}
else
{
return validationstatus;
}
}
}
Basically what I'd like to do is call that method inside the webcommon class, inside the model itself to check when I take in the values for the get;sets in my model, and if it returns false, then I want it to throw an error within the view saying that it is not a valid input. Thanks!
This question here is about making custom regular expression attrbutes and should answer your question.
Check out either Regular Expression Attribute
Or implement and IValidatableObject

Generic save method

In my generic repository I need to write generic Save method which will edit existed or add new entity depending on id.
public void Save<T>(T entity) where T : TEntity, IKeyId
{
if (ObjectSet.Any(r => (r as IKeyId).KeyId == entity.KeyId))
{
Edit(entity);
}
else
{
Add(entity);
}
}
But Linq generate exception when I try do Any( r=> (r as IKeyId)....
The 'TypeAs' expression with an input of type 'MyProg.DAL.Appeal' and a check of type 'Claimstrak.DAL.Interfaces.IKeyId' is not supported. Only entity types and complex types are supported in LINQ to Entities queries.
How to write it correct?
Well, the truth is that you dont need to use the ObjectSet, you can just use DbContext to do this, in a much more easy way.
Bu, i would tell that this is not a good pattern to use, to call a Save() in a repository. I would recomend that you consider the .SaveSession() of the Context only after all was done, this way you can do a lot of things befose making a round trip to te database.
So, you should make a method like this, but not call the SaveChanges(), instead of a Save() method, to a UpdateOrInsert() and them, after all is done you call the .Save()
But i will give the examplefollowing your request (but i dont recommend, i recommend you separate IUnitOfWork from IRepository)
See how the code is very simple:
interface IKeyId
{
int Id { get; set; }
}
DbContext context = new YourContext();
public bool Save<TEntity>(TEntity entity) where TEntity : class, IKeyId
{
return (entity.Id == 0) ? Add<TEntity>(entity) : Edit<TEntity>(entity);
}
public bool Edit<TEntity>(TEntity entity) where TEntity : class, IKeyId
{
var set = context.Set<TEntity>();
set.Attach(entity);
return true;
}
public bool Add<TEntity>(TEntity entity) where TEntity : class, IKeyId
{
var set = context.Set<TEntity>();
set.Add(entity);
return true;
}
I use a similar approach im my repositories, i have changed the T4 (.tt file) that generates the POCO classes from my database to excplicitly implement some interfaces that i have, such as IAuditable, IValidatable and other, so the T4 automaticaly implement those interfaces in the classes.

Automapper + EF4 + ASP.NET MVC - getting 'context disposed' error (I know why, but how to fix it?)

I have this really basic code in a MVC controller action. It maps an Operation model class to a very basic OperationVM view-model class .
public class OperationVM: Operation
{
public CategoryVM CategoryVM { get; set; }
}
I need to load the complete list of categories in order to create a CategoryVM instance.
Here's how I (try to) create a List<OperationVM> to show in the view.
public class OperationsController : Controller {
private SomeContext context = new SomeContext ();
public ViewResult Index()
{
var ops = context.Operations.Include("blah...").ToList();
Mapper.CreateMap<Operation, OperationVM>()
.ForMember(
dest => dest.CategoryVM,
opt => opt.MapFrom(
src => CreateCatVM(src.Category, context.Categories)
// trouble here ----------------^^^^^^^
)
);
var opVMs = ops.Select(op => Mapper.Map<Operation, OperationVM>(op))
.ToList();
return View(opVMs);
}
}
All works great first time I hit the page. The problem is, the mapper object is static. So when calling Mapper.CreateMap(), the instance of the current DbContext is saved in the closure given to CreateMap().
The 2nd time I hit the page, the static map is already in place, still using the reference to the initial, now disposed, DbContext.
The exact error is:
The operation cannot be completed because the DbContext has been disposed.
The question is: How can I make AutoMapper always use the current context instead of the initial one?
Is there a way to use an "instance" of automapper instead of the static Mapper class?
If this is possible, is it recommended to re-create the mapping every time? I'm worried about reflection slow-downs.
I read a bit about custom resolvers, but I get a similar problem - How do I get the custom resolver to use the current context?
It is possible, but the setup is a bit complicated. I use this in my projects with help of Ninject for dependency injection.
AutoMapper has concept of TypeConverters. Converters provide a way to implement complex operations required to convert certain types in a separate class. If converting Category to CategoryVM requires a database lookup you can implement that logic in custom TypeConverter class similar to this:
using System;
using AutoMapper;
public class CategoryToCategoryVMConverter :
TypeConverter<Category, CategoryVM>
{
public CategoryToCategoryVMConverter(DbContext context)
{
this.Context = context;
}
private DbContext Context { get; set; }
protected override CategoryVM ConvertCore(Category source)
{
// use this.Context to lookup whatever you need
return CreateCatVM(source, this.Context.Categories);
}
}
You then to configure AutoMapper to use your converter:
Mapper.CreateMap<Category, CategoryVM>().ConvertUsing<CategoryToCategoryVMConverter>();
Here comes the tricky part. AutoMapper will need to create a new instance of our converter every time you map values, and it will need to provide DbContext instance for constructor. In my projects I use Ninject for dependency injection, and it is configured to use the same instance of DbContext while processing a request. This way the same instance of DbContext is injected both in your controller and in your AutoMapper converter. The trivial Ninject configuration would look like this:
Bind<DbContext>().To<SomeContext>().InRequestScope();
You can of course use some sort of factory pattern to get instance of DbContext instead of injecting it in constructors.
Let me know if you have any questions.
I've found a workaround that's not completely hacky.
Basically, I tell AutoMapper to ignore the tricky field and I update it myself.
The updated controller looks like this:
public class OperationsController : Controller {
private SomeContext context = new SomeContext ();
public ViewResult Index()
{
var ops = context.Operations.Include("blah...").ToList();
Mapper.CreateMap<Operation, OperationVM>()
.ForMember(dest => dest.CategoryVM, opt => opt.Ignore());
var opVMs = ops.Select(
op => {
var opVM = Mapper.Map<Operation, OperationVM>(op);
opVM.CategoryVM = CreateCatVM(op.Category, context.Categories);
return opVM;
})
.ToList();
return View(opVMs);
}
}
Still curious how this could be done from within AutoMapper...
The answer from #LeffeBrune is perfect. However, I want to have the same behavior, but I don't want to map every property myself. Basically I just wanted to override the "ConstructUsing".
Here is what I came up with.
public static class AutoMapperExtension
{
public static void ConstructUsingService<TSource, TDestination>(this IMappingExpression<TSource, TDestination> mappingExression, Type typeConverterType)
{
mappingExression.ConstructUsing((ResolutionContext ctx) =>
{
var constructor = (IConstructorWithService<TSource, TDestination>)ctx.Options.ServiceCtor.Invoke(typeConverterType);
return constructor.Construct((TSource)ctx.SourceValue);
});
}
}
public class CategoryToCategoryVMConstructor : IConstructorWithService<Category, CategoryVM>
{
private DbContext dbContext;
public DTOSiteToHBTISiteConverter(DbContext dbContext)
{
this.dbContext = dbContext;
}
public CategoryVM Construct(Category category)
{
// Some commands here
if (category.Id > 0)
{
var vmCategory = dbContext.Categories.FirstOrDefault(m => m.Id == category.Id);
if (vmCategory == null)
{
throw new NotAllowedException();
}
return vmCategory;
}
return new CategoryVM();
}
}
// Initialization
Mapper.Initialize(cfg =>
{
cfg.ConstructServicesUsing(type => nInjectKernelForInstance.Get(type));
cfg.CreateMap<Category, CategoryVM>().ConstructUsingService(typeof(CategoryToCategoryVMConstructor));
};

Adding DataAnnotation to class when using FluentValidation

I use the FluentValidation framework to add validation and annotations to my models in an MVC project.
I need to add data annotations to the class level of a model. Namely, the model needs to have the DisplayColumn attribute added. But, since I use FluentValidation (and have the application's ModelMetadataProvider set to use FluentValidation), even if I put the DisplayColumn attribute on the model class, it isn't used. However, I can't find a way to add that annotation by using FluentValidation.
Does anyone have any idea how I can get that to work?
Thanks
I wouldn't actually recommend using the FluentValidationModelMetadataProvider - this was only really ever an experimental addition (which very well may be removed from the next release), and it doesn't support any of the class-level DataAnnotations (such as DisplayColumn). I would suggest that you use FluentValidation only for validation, but stick with attributes for metadata.
That being said, if you really want to get this working then you could implement by using a custom no-op validator that's used only for metadata:
public static class MetadataExt {
public static IRuleBuilderOptions<T, TProperty> DisplayColumn<T, TProperty>(this IRuleBuilder<T, TProperty> rule) {
var ruleBuilder = (FluentValidation.Internal.RuleBuilder<T, TProperty>)rule;
ruleBuilder.Rule.AddValidator(new DisplayColumnWrapper(ruleBuilder.Rule.PropertyName));
return ruleBuilder;
}
public class DisplayColumnWrapper : NoopPropertyValidator, IAttributeMetadataValidator {
private string name;
public DisplayColumnWrapper(string name) {
this.name = name;
}
public override IEnumerable<ValidationFailure> Validate(PropertyValidatorContext context) {
return Enumerable.Empty<ValidationFailure>();
}
public Attribute ToAttribute() {
return new DisplayColumnAttribute(name);
}
}
}
... Which you could then use like this:
public class Validator : AbstractValidator<SomeModel> {
public Validator() {
RuleFor(x => x.DisplayColumnProperty)
.DisplayColumn();
}
}
You'd then need to create a custom ModelMetadataProvider that knows how to process this:
public class ExtendedFVModelMetadataProvider : FluentValidationModelMetadataProvider {
IValidatorFactory _validatorFactory;
public ExtendedFVModelMetadataProvider(IValidatorFactory validatorFactory)
: base(validatorFactory) {
this._validatorFactory = validatorFactory;
}
public override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType) {
var validator = _validatorFactory.GetValidator(modelType);
if (validator == null) {
return base.GetMetadataForType(modelAccessor, modelType);
}
// Only look for the DisplayColumnWrapper
// There is a mismatch as MVC expects this to be defined at class-level, but FV defines everything at the property level.
var displayColumns = from memberWithValidator in validator.CreateDescriptor().GetMembersWithValidators()
from propertyValidator in memberWithValidator
let wrapper = propertyValidator as MetadataExt.DisplayColumnWrapper
where wrapper != null
select wrapper.ToAttribute();
var displayColumn = displayColumns.FirstOrDefault();
// we found a displaycolumn, so pass it over to MVC to build the metadata.
if (displayColumn != null) {
return CreateMetadata(new[] { displayColumn }, null /* containerType */, modelAccessor, modelType, null /* propertyName */);
}
return base.GetMetadataForType(modelAccessor, modelType);
}
}
The provider overrides the GetMetadataForModel method and looks for any properties that use DisplayColumn. This could probably be extended if you want to support any other custom metadata extensions too. You could then use this provider in place of the metadata provider that comes with FluentValidation.
However, I still wouldn't recommend this approach...the library is designed for performing validation, not for generating UI metadata.

Resources