.net core data annotation display Name - inherite to viewmodels - c#

I am trying to create a ASP.NET application, and am using DataAnnotations in the Entity Class Models for more readable display names:
In my ApplicationDomain Project
public class Car{
public int Id { get; set; }
[Display(Name = "Make of Car")]
public string Make { get; set; }
[Display(Name = "Year of Purchase")]
public int PurchaseYear { get; set; }
}
When I then use this as the model for my views, everything is displayed as expected.
But when I use a view model, I then have to add the Annotations again as the Display Name I initially added to Car is not 'Inherited' to the View Models based on it.
In my WebMVC Project
public class EditCarViewModel{
[Display(Name = "Make of Car")]
public string Make { get; set; }
[Display(Name = "Year of Purchase")]
public int PurchaseYear { get; set; }
}
The same for the create, index and any other views that use a viewmodel and not the Car Class.
Is there anyway to have the annotations that are in the initial entity class model inherited / propagated up, into the related view models so I'm not having to do this in multiple places?
I think this will be even more of an issue if I then try to add a different UI project. e.g. a desktop application in addition to the WebMVC.
It would be ideal if the labels for both could be based on the definitions in the ApplicationDomain Project.

You can try creating a new metadata class and apply it to your others.
[MetadataType(typeof(CarModelMetaData))]
public class EditCarViewModel{
public string Make { get; set; }.
public int PurchaseYear { get; set; }
}
[MetadataType(typeof(CarModelMetaData))]
public class CreateCarViewModel{
public string Make { get; set; }
public int PurchaseYear { get; set; }
}
public class CarModelMetaData{
[Display(Name = "Make of Car")]
public string Make { get; set; }
[Display(Name = "Year of Purchase")]
public int PurchaseYear { get; set; }
}

There is no way of propagating annotation text from one class to another.
But if you just want to keep the same text in one place, you can create constants and use them this way:
public static class DisplayConstants
{
public const string Make = "Make of Car";
public const string PurchaseYear = "Year of Purchase";
}
public class EditCarViewModel{
[Display(Name = DisplayConstants.Make)]
public string Make { get; set; }
[Display(Name = DisplayConstants.PurchaseYear)]
public int PurchaseYear { get; set; }
}
public class Car
{
public int Id { get; set; }
[Display(Name = DisplayConstants.Make)]
public string Make { get; set; }
[Display(Name = DisplayConstants.PurchaseYear)]
public int PurchaseYear { get; set; }
}
Note that this way you can name properties in EditCarViewModel and Car whatever way you like, no restriction on consistent naming.

Related

Reusing C# class in MVC C#

I have an application that can contain a minimum of one "person" up to a maximum of fours "persons". I am using view models and manually mapping in the controller to the domain model.
I am completely lost as to how to include more than one "person" in the app. I've read up on using for but can't wrap my head around it.
Right now, I am just adding the data from the "person" class manually such that
Code:
public class SomeClass
{
public Guid SomeClassId {get; set;}
public string BorrowerFirst { get; set; }
public string BorrowerMI { get; set; }
public string BorrowerLast { get; set; }
public Suffix? BorrowerSuffix { get; set; }
... some more fields ...
}
and so on in the master class.
What I'd like to do is use a class such as:
Code:
public class Applicant
{
public string BorrowerFirst { get; set; }
public string BorrowerMI { get; set; }
public string BorrowerLast { get; set; }
public Suffix? BorrowerSuffix { get; set; }
}
can be reused in another class multiple times.
How can I separate that to strip that and instead use a named class consisting of first, middle and last names and allowing up to four "person" instances in my master class?
Have you tried inheritance?
public class Person
{
public Guid SomeClassId {get; set;}
public string BorrowerFirst { get; set; }
public string BorrowerMI { get; set; }
public string BorrowerLast { get; set; }
public Suffix? BorrowerSuffix { get; set; }
}
and the Applicant class:
public class Applicant : Person
{
//Only extra properties and methods here.
public string FullName
{
get
{
return this.BorrowerFirst + " " + this.BorrowerMI + " " + this.BorrowerLast;
}
}
}
You can then have a vendor as well:
public class Vendor: Person
{
//Only extra properties and methods here.
}

entity framework c# eager loading inherited and nested properties

I have a following object as a model in project:
AbstractControll and AntivirusControll which inherits from AbstractControll.
public class AntivirusControll: AbstractControll
AnticvirusControll has property:
public List<Exclusion> Exclusions { get; set; }
And this part of code drives me creazy:
var a = _entities.AntivirusControlls.First(m => m.Id == 1);
var b = _entities.AbstractControlls.First(m => m.Id == 1);
In database AnticvirusControll has one exception,while in result of executing above code I get:
a.Exclusions - has one object ( which is great and ok )
b.Exclusions - has none!
How is it even called inheritance? It's not polymorphic, it's .... a bug I could tell. Lazy loading wont work in this case.
And while asking for AbstractControlls I Can't include any property from derivered class offcourse.
Any ideas how to fix it?
--EDIT
both classes;
public abstract class AbstractControll
{
public int Id { get; set; }
}
public abstract class AbstractControll
{
public int Id { get; set; }
}
public class AntivirusControll: AbstractControll
{
public class Exclusion
{
public int Id { get; set; }
[DataMember]
[Display(Name = "Object Type")]
public String ObjectType { get; set; }
[DataMember]
[Display(Name = "Object Type")]
public String ObjectName { get; set; }
[DataMember]
public ConfigurationItemDescription ExlusionCI { get; set; }
}
[Display(Name= "Is Antyvirus Enabled")]
[DataMember]
public bool? isAntyvirusEnabled { get; set; }
[DataMember]
public ConfigurationItemDescription isAntyvirusEnabledCI { get; set; }
[DataMember]
[Display(Name = "Is real time protection enabled")]
public bool? isRealTimeProtectionEnabled { get; set; }
[DataMember]
public ConfigurationItemDescription isRealTimeProtectionEnabledCI { get; set; }
[DataMember]
[Display(Name = "Virus definition not older than( in days)")]
[Required]
[Range(typeof(int),"1","365")]
public int? VirusDefinitionNotOlderThen { get; set; }
[DataMember]
public ConfigurationItemDescription VirusDefinitionNotOlderThenCI { get; set; }
[DataMember]
public List<Exclusion> Exclusions { get; set; }
public AntivirusControll()
{
isAntyvirusEnabled = true;
isRealTimeProtectionEnabled = true;
VirusDefinitionNotOlderThen = 7;
isAntyvirusEnabledCI = new ConfigurationItemDescription();
isRealTimeProtectionEnabledCI = new ConfigurationItemDescription();
VirusDefinitionNotOlderThenCI = new ConfigurationItemDescription();
Exclusions = new List<Exclusion>();
}
}
--Edit 2
Well... I wanto to clarify, what actualy I'm doing.
I have MVC + angular Application.
There is a document with some Controls( AbstractControll)
Each of them is specific Type for example: Antivirus, Encryption and so on. At this point I have about 20 of them, but I will have more probably. Most of those derived classes have inner classes like Exceptions in Antivirus.
Right.
Basicaly that's it. What is important- After getting "AbstractControll" I want to expose this object over webapi - so lazy loading is not applicable here( or maybe it could be?)
That's it. It runtime I don't know exat type of the controll, so I Can't Include Properties from for example "Antivirus", when operating on DbSet
What I have now is ugly if's block that returns propper object and includes everything, but i'm not happy about his "hack".

How to Add Attributes to .cs file generated by Entity Framework

I am creating a ASP.net MVC web app and trying to add validation attributes to a ClientsTbl.cs file I have generated from a SQL server using entity framework. I have done scaffolding and created the view and the controller for the Table(Model), but for some reason the scaffold did not recognize the primary key column as a primary key. On top of that it will not let me add attributes in []. I can't even change the field description that appears above the views form text box. How do I do the above in the following class?
namespace Testit.Models
{
using System;
using System.Collections.Generic;
public partial class ClientsTbl
{
public ClientsTbl()
{
this.ProgramClientTbls = new HashSet<ProgramClientTbl>();
}
public int id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int CenterId { get; set; }
public string MiddleName1 { get; set; }
public string MiddleName2 { get; set; }
public System.DateTime DateAdded { get; set; }
public virtual CenterTbl CenterTbl { get; set; }
public virtual ICollection<ProgramClientTbl> ProgramClientTbls { get; set; }
}
}
You can create a metadata class to do that. For example, if Id, FirstName, and LastName are required fields, you can create a new class like below.
public class ClientsTblMetadata
{
[Required()]
public int Id { get; set; }
[Required()]
public string FirstName { get; set; }
[Required()]
public string LastName { get; set; }
}
Then you need to add a new partial class with a MetadataType attribute. Please make sure that this class is located under the same namespace, otherwise it won't work.
namespace Testit.Models
{
[MetadataType(typeof(ClientsTblMetadata))] // you need this line of code.
public partial class ClientsTbl

View Model implementation - less fields than in entities

I have two entities: Person and Quote (in one to many relationship)
Person:
public class Person
{
public int PersonID { get; set; }
[Required]
[StringLength(20]
public string Name { get; set; }
[StringLength(30]
public string Relation { get; set; }
public byte[] Image { get; set; }
[StringLength(50)]
public string ImageMimeType { get; set; }
public virtual ICollection<Quote> Quotes { get; set; }
}
Quote:
public class Quote
{
public int QuoteID { get; set; }
public int PersonID { get; set; }
[Required]
[StringLength(200)]
public string QuoteName { get; set; }
[StringLength(400)]
public string Context { get; set; }
public DateTime? Date { get; set; }
public virtual Person Person { get; set; }
}
I want to make a ViewModel for displaying quotes in short format - I need just a few properties - Person Name, QuoteName and Person Image. I could do something casual like they're showing in every ASP.NET MVC tutorial:
public class QuoteViewModel
{
public IEnumerable<Quote> Quotes { get; set; }
}
Is there a better way rather than creating IEnumerable with type of Quote and loading all properties?
How about creating QuoteShort model and making QuoteViewModel as IEnumerable<QuoteShort> QuotesShort.
In controller I would map every 3 fields from repository to QuoteShort and add it to QuotesShort IEnumerable (even though I don't know how to persist them to QuotesShort IEnumerable )
Some examples appreciated.
You can make a QuoteShort ViewModel with just the few properties you need, and then have your view expect IEnumerable<QuoteShort> as its model. You don't necessarily have to wrap that up in another container.
If you have this:
public class QuoteShort{
public Person Person {get;set;}
public string Name {get; set;}
// etc
}
You can do this in the controller:
var quotes = //however you get your list of quotes
var model = (from q in quotes select new QuoteShort
{ Person = q.Person, Name = q.Name /*etc*/ }).ToList();
return View(model);
What about something like
public class QuotesShortViewModel
{
public IEnumerable<QuoteShortViewModel> QuotesShort { get; set; }
}
public class QuoteShortViewModel
{
// ... the properties you need
}
Create a View that receives a QuotesShortViewModel and iterates through the list, rendering the short quotes as it pleases you.
AutoMapper is useful to map between Models and ViewModels in your controllers.

How should I handle lookups in my ViewModel?

My database table for buildings stores the building type as a code. In a separate lookup table the description for that code is stored.
How should I design my ViewModel and where will I need to make the call to get the associated description value?
I sort of can see one option. I want to know if there is a better option.
BuildingViewModel
{
public string BuildingTypeCode { get;set;}
...other properties
}
Then in my view
code...
<p>#MyService.GetDescription(Model.BuildingTypeCode)</p>
...code
Am I incorrect in the way I am thinking? if I do the above I create a dependency in my View to the service?
Update 1
Working through some of the solutions offered. I seem to run into another issue. I can't access the constructor of each building directly...
public ViewResult Show(string ParcelId)
{
var result = _service.GetProperty(ParcelId);
var AltOwners = _service.GetAltOwners(ParcelId);
var Buildings = _service.GetBuildings(ParcelId);
ParcelDetailViewModel ViewModel = new ParcelDetailViewModel();
ViewModel.AltOwnership = new List<OwnerShipViewModel>();
ViewModel.Buildings = new List<BuildingViewModel>();
AutoMapper.Mapper.Map(result, ViewModel);
AutoMapper.Mapper.Map<IEnumerable<AltOwnership>, IEnumerable<OwnerShipViewModel>>(AltOwners,ViewModel.AltOwnership);
AutoMapper.Mapper.Map<IEnumerable<Building>, IEnumerable<BuildingViewModel>>(Buildings, ViewModel.Buildings);
ViewModel.Pool = _service.HasPool(ParcelId);
ViewModel.Homestead = _service.IsHomestead(ParcelId);
return View(ViewModel);
}
public class ParcelDetailViewModel
{
public IEnumerable<OwnerShipViewModel> AltOwnership { get; set; }
//public IEnumerable<ValueViewModel> Values { get; set; }
public IEnumerable<BuildingViewModel> Buildings { get; set; }
//public IEnumerable<TransferViewModel> Transfers { get; set; }
//public IEnumerable<SiteAddressViewModel> SiteAddresses { get; set; }
public string ParcelID { get; set; }
//public string ParcelDescription { get; set; }
//public int LandArea { get; set; }
//public string Incorporation { get; set; }
//public string SubdivisionCode {get;set;}
public string UseCode { get; set; }
//public string SecTwpRge { get; set; }
//public string Census { get; set; }
//public string Zoning { get; set; }
public Boolean Homestead {get;set;}
//public int TotalBuildingArea { get; set; }
//public int TotalLivingArea { get; set; }
//public int LivingUnits { get; set; }
//public int Beds { get; set; }
//public decimal Baths { get; set; }
public short Pool { get; set; }
//public int YearBuilt { get; set; }
}
My understanding is that the view model is meant for display ready data. I think the real problem here is putting model dependent logic into the view.
You can do your service lookup but keep that code in the controller. The view model should be considered display ready (save for some formatting).
class BuildingViewModel
{
public string BuildingTypeCode { get;set;}
...other properties
}
and then do the lookup before you render:
public ActionResult Building()
{
var typeCode = // get from original source?
var model = new BuildingViewModel
{
BuildingTypeCode = MyService.GetDescription(typeCode)
};
return View("Building", model);
}
Having come from a long line of JSP custom tags I dread having any code hidden in the view layout. IMO, that layer should be as dumb as possible.
I would recommend having a helper that does that, or a DisplayTemplate
public class ViewHelpers
{
public static string GetDescription(string code)
{
MyService.GetDescription(Model.BuildingTypeCode);
}
}
or
#ModelType string
#Html.DisplayFor("",MyService.GetDescription(Model.BuildingTypeCode));
More info on templates: http://www.headcrash.us/blog/2011/09/custom-display-and-editor-templates-with-asp-net-mvc-3-razor/
Both of these approaches introduce a dependency on your service but you can test/change them in one single place, instead of the whole application (plus the usage looks cleaner).

Categories