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).
Related
Firstly, apologies if this seems basic, I am new to C#/dotnet and if the answer to this questions is somewhere obvious please point me in the right direction.
I have a DTO class with the following code
public class LessonDetailView : BaseResult
{
public long Id { get; set; }
public string Title { get; set; }
public List<LessonImagesListView> LessonImages { get; set; }
public List<LessonInstructionCardListView> InstructionCards { get; set; }
}
public class LessonImagesListView
{
public long Id { get; set; }
public string Title { get; set; }
public ImageDetailView Image { get; set; }
public LessonImagesListView()
{
Image = new ImageDetailView();
}
}
public class LessonInstructionCardListView
{
public long Id { get; set; }
public string Instructions { get; set; }
}
So I have 2 distinct types of object that I attach to the lesson and send to the frontend.
I will add that in the future I might have 6 different types of object.
These Images, or Instructions are also going to be displayed in a certain order on the front end so instead of sending them all separately I wanted to combine them all and send them in a new List LessonAssetsListView for example.
How can i create Lists in a DTO that combine 2 other lists ?
OR ... is this something I even need to do here ... and can i just do all this in my service.
Help appreciated.
You could simply define a type that composes both your existing and send a List of them
public class LessonAsset
{
public LessonImagesListView Image {get;set; }
public LessonInstructionCardListView Instruction {get;set;}
}
and then
public class LessonDetailView : BaseResult
{
public long Id { get; set; }
public string Title { get; set; }
public List<LessonAsset> LessonAssets { get; set; }
}
EDIT: I originally worded this question very poorly, stating the problem was with JSON serialization. The problem actually happens when I'm converting from my base classes to my returned models using my custom mappings. I apologize for the confusion. :(
I'm using .NET Core 1.1.0, EF Core 1.1.0. I'm querying an interest and want to get its category from my DB. EF is querying the DB properly, no problems there. The issue is that the returned category has a collection with one interest, which has one parent category, which has a collection with one interest, etc. When I attempt to convert this from the base class to my return model, I'm getting a stack overflow because it's attempting to convert the infinite loop of objects. The only way I can get around this is to set that collection to null before I serialize the category.
Interest/category is an example, but this is happening with ALL of the entities I query. Some of them get very messy with the loops to set the relevant properties to null, such as posts/comments.
What is the best way to address this? Right now I'm using custom mappings that I wrote to convert between base classes and the returned models, but I'm open to using any other tools that may be helpful. (I know my custom mappings are the reason for the stack overflow, but surely there must be a more graceful way of handling this than setting everything to null before projecting from base class to model.)
Classes:
public class InterestCategory
{
public long Id { get; set; }
public string Name { get; set; }
public ICollection<Interest> Interests { get; set; }
}
public class Interest
{
public long Id { get; set; }
public string Name { get; set; }
public long InterestCategoryId { get; set; }
public InterestCategory InterestCategory { get; set; }
}
Models:
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public long? InterestCategoryId { get; set; }
}
Mapping functions:
public static InterestCategoryModel ToModel(this InterestCategory category)
{
var m = new InterestCategoryModel
{
Name = category.Name,
Description = category.Description
};
if (category.Interests != null)
m.Interests = category.Interests.Select(i => i.ToModel()).ToList();
return m;
}
public static InterestModel ToModel(this Interest interest)
{
var m = new InterestModel
{
Name = interest.Name,
Description = interest.Description
};
if (interest.InterestCategory != null)
m.InterestCategory = interest.InterestCategory.ToModel();
return m;
}
This is returned by the query. (Sorry, needed to censor some things.)
This is not .NET Core related! JSON.NET is doing the serialization.
To disable it globally, just add this during configuration in Startup
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}));
edit:
Is it an option to remove the circular references form the model and have 2 distinct pair of models, depending on whether you want to show categories or interests?
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Note that each of the models has a nested class for it's child objects, but they have their back references removed, so there would be no infinite reference during deserialization?
My task is to show multiple models into a single view.I've created a ViewModel for my requirement but I'm not meeting my requirement.
please have a look into the below code and rectify me where m i going wrong ???
public partial class StudentsDetail
{
public int StudentID { get; set; }
public int ParentID { get; set; }
public string StudentName { get; set; }
public string Gender { get; set; }
public string FatherName { get; set; }
public string MotherName { get; set; }
public Nullable<System.DateTime> DateOfBirth { get; set; }
public virtual ParentsDetail ParentsDetail { get; set; }
public virtual SchoolDetail SchoolDetail { get; set; }
}
//Model 2
public partial class ParentsDetail
{
public ParentsDetail()
{
this.StudentsDetails = new HashSet<StudentsDetail>();
}
public int ParentID { get; set; }
public string Occupation { get; set; }
public string Organization { get; set; }
public string AnnualIncome { get; set; }
public virtual ICollection<StudentsDetail> StudentsDetails { get; set; }
}
//ViewModel Which I have created
public class ParentsInformationViewModel
{
public List<StudentsDetail> StudentsDetails { get; set; }
public List<ParentsDetail> ParentsDetails { get; set; }
public ParentsInformationViewModel(List<StudentsDetail> _studentDetails, List<ParentsDetail> _parentsDetails) //Should i pass all the required parameters that i want to display in view ????
{
StudentsDetails = _studentDetails;
ParentsDetails = _parentsDetails;
}
//And finally this is my method defined in the StudentController (Have i defined it in a right place/way??)
public ActionResult StudentViewModel()
{
ViewBag.ParentsDetail = new ParentsDetail(); //ParentsDetail is my controller
List<StudentsDetail> studentListObj = StudentsDetailsDAL.GetStudentDetails();
List<ParentsInformationViewModel> ParentInfoVMObj = new List<ParentsInformationViewModel>();
//foreach (var student in studentListObj)
//{
// ParentInfoVMObj.Add(new ParentsInformationViewModel(student.StudentID, student.ParentID));
//}
//ParentInfoVMObj.Add(ParentInfoVMObj); /// don't know how to call the required viewmodel
return View(ParentInfoVMObj);
}
I know that the above method of a ViewModel is wrong but how to use it or where am i going wrong I can't get.
I want to display the ViewModel in the view as a detailed view .
Please, correct me as I'm a starter in MVC3 .
Thanks In Advance!!
In your controller, define your action method as follows.
public ActionResult ParentsDetails()
{
var studentDetails = new List<StudentDetail>();
var parentDetails = new List<ParentsDetail>();
// Fill your lists here, and pass them to viewmodel constructor.
var viewModel = new ParentsInformationViewModel(studentDetails, parentDetails)
// Return your viewmodel to corresponding view.
return View(viewModel);
}
In your view define your model.
#model MySolution.ViewModels.ParentsInformationViewModel
Is there in your view declared that you are receiving model of type
In view:
#model IEnumerable<ParentsInformationViewModel>
I am getting some post data from an HTML form. The data that comes up is used to build a TextualReport object. I want to parse the various pieces of form data that come up and populate those parts of my model.
The reason i am not using a model binder is this is a fairly complex object and indices of my lists can be missing (start at 2, skip 3 etc..). I am starting with an existing object, and only replacing the properties that came up in the post.
I have the following object called TextualReport.
public class TextualReport {
public IList<Section> Sections { get; set; }
public IList<string> MiscInputs { get; set; }
public TextualReport(){
Sections = new List<Section>();
MiscInputs = new List<string>();
}
}
public class Section{
public Section(){
Id = Guid.NewGuid();
Blocks = new List<Block>();
}
public Guid Id { get; set; }
public string Heading { get; set; }
public IList<Block> Blocks { get; set; }
}
public class Block{
public Block(){
PreGraphText = new List<string>();
PreGraphInput = new List<string>();
Graphs = new List<Graph>();
PostGraphText = new List<string>();
}
public Guid Id { get; set; }
public string Heading { get; set; }
public IList<string> PreGraphText { get; set; }
public IList<Graph> Graphs { get; set; }
public IList<string> PostGraphText { get; set; }
public IList<string> PreGraphInput { get; set; }
}
public class Graph{
public string Url { get; set; }
public string Caption { get; set; }
}
From my HTML/Razor form, I get a sequence of text strings like the following:
TextualReport.Sections[1].Blocks[0].Graphs[0].Caption=
TextualReport.Sections[1].Blocks[0].Graphs[1].Caption=
TextualReport.Sections[1].Blocks[0].Graphs[2].Caption=
TextualReport.Sections[1].Blocks[0].PreGraphInput[0]=
TextualReport.Sections[1].Blocks[0].PreGraphInput[1]=
TextualReport.Sections[1].Blocks[1].Graphs[0].Caption=
TextualReport.Sections[1].Blocks[1].PreGraphInput[0]=
TextualReport.Sections[1].Blocks[1].PreGraphInput[1]=
TextualReport.Sections[1].Blocks[2].Graphs[0].Caption=
TextualReport.Sections[1].Blocks[2].Graphs[1].Caption=
TextualReport.Sections[1].Blocks[2].PreGraphInput[0]=
TextualReport.Sections[1].Blocks[2].PreGraphInput[1]=
TextualReport.Sections[1].Blocks[3].Graphs[0].Caption=
TextualReport.Sections[1].Blocks[3].PreGraphInput[0]=
TextualReport.Sections[1].Blocks[3].PreGraphInput[1]=
TextualReport.Sections[1].Blocks[4].Graphs[0].Caption=
TextualReport.Sections[1].Blocks[4].PreGraphInput[0]=
TextualReport.Sections[1].Blocks[4].PreGraphInput[1]=
What would be the best approach to populate my existing data with the various pieces that came up in the form post? I get the model from the database, then update based on the new data.
I have a number of classes that are all related conceptually, but some more-so at the details level than others. For example, these three classes have nearly identical properties (although member functions will vary):
public class RelatedA : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
}
public class RelatedB : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
}
public class RelatedC : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
public int Special { get; set; }
}
There are a couple of other classes that are conceptually related to the above 3, but can be a bit different implementation-wise:
public class RelatedD : IRelatedType
{
public string Name { get; set; }
public string Statement { get; set; }
}
public class RelatedE : IRelatedType
{
public string Name { get; set; }
public string Statement { get; set; }
public bool IsNew { get; set; }
}
Instances of these can be created by a factory based on some sort of "type" enumerated value. The problem is that later on when these objects are being used (in a business layer, for example), there could be a lot of code like this:
IRelatedType theObject = TheFactory.CreateObject(SomeEnum.SomeValue);
if (theObject is RelatedC)
{
RelatedC cObject = theObject as RelatedC;
specialVal = cObject.Special;
}
else if (theObject is RelatedD)
{
RelatedD dObject = theObject as RelatedD;
statementVal = dObject.Statement;
}
else if (theObject is RelatedE)
{
RelatedE eObject = theObject as RelatedE;
statementVal = eObject.Statement;
isNewVal = eObject.IsNew;
}
This could be repeated in many places. Is there a better approach to the design that I should be using (there's got to be)?
You could try and factor the differences into seperate classes that are then provided so for example:
IRelatedType theObject = TheFactory.CreateObject(SomeEnum.SomeValue);
RelatedTypeHelper theHelper=TheFactory.CreateHelper(theObject);
theHelper.DoSpecialThing(theObject);
Now you won't have to have all the if else blocks, and if you add a new type which requires new handling, you just whip up a new helper implement the required pieces and you should be good to go. The helper should help document this process.
I would also question why a single method would have such a different implementation for specialVal and StatementVal could be your sample, but It makes me curious what your really doing here. can you simplify things back taking a step back and questioning the point of these being included in this specific hierarchy.