XSD2Code, Is it possible to serialize inherited properties from a parent abstract class? - xsd2code

I have a XSD2Code generated Class and all is working. However I want to generate and store IDs as GUIDs on all Complex class types ie Order, OrderItem etc. to facilitate CRUD from the object Hierarchy. So instead of adding an ID element to every "Record" style dataset in the XML Schema I have created a parent abstract Class from which my XSD2Code classes inherits from. My code can see the ID, and it generates the ID, however it seems that XSD2Code does not see ID and thus ID does not get Serialized.
My Parent Class code:
namespace OrderSystem
{
public abstract class Master
{
private string IdField;
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 999)]
public String ID
{
get
{
if (IdField == null)
{
IdField = Guid.NewGuid().ToString();
}
return IdField;
}
}
}
}
Which is used by my XSD generated code:
public partial class Product : Master
{
My instinct is that ID is not being serialized, because it is not in the generated class ie "Product" which is a little odd since the rest of the code can see it because it is inherited.
Any thoughts please?
EDIT:
public class Master
{
private string IdField;
[System.Xml.Serialization.XmlAttributeAttribute()]
public String ID
{
get
{
//if (IdField == null)
//{
// IdField = Guid.NewGuid().ToString();
//}
return IdField;
}
set
{
if (value == null)
{
IdField = Guid.NewGuid().ToString();
}
else
{
IdField = value;
}
}
}
}

I sorted this myself. Proved to be an error in the code. Also I removed the "Abstract", not sure if this is necessary. See EDIT above.

Related

How to code a Polymorphic Model Binder and Provider in MVC 6

This question has been asked before on SO and elsewhere in the context of MVC3 and there are bits and bobs about it related to ASP.NET Core RC1 and RC2 but niot a single example that actually shows how to do it the right way in MVC 6.
There are the following classes
public abstract class BankAccountTransactionModel {
public long Id { get; set; }
public DateTime Date { get; set; }
public decimal Amount { get; set; }
public readonly string ModelType;
public BankAccountTransactionModel(string modelType) {
this.ModelType = modelType;
}
}
public class BankAccountTransactionModel1 : BankAccountTransactionModel{
public bool IsPending { get; set; }
public BankAccountTransactionModel1():
base(nameof(BankAccountTransactionModel1)) {}
}
public class BankAccountTransactionModel2 : BankAccountTransactionModel{
public bool IsPending { get; set; }
public BankAccountTransactionModel2():
base(nameof(BankAccountTransactionModel2)) {}
}
In my controller I have something like this
[Route(".../api/[controller]")]
public class BankAccountTransactionsController : ApiBaseController
{
[HttpPost]
public IActionResult Post(BankAccountTransactionModel model) {
try {
if (model == null || !ModelState.IsValid) {
// failed to bind the model
return BadRequest(ModelState);
}
this.bankAccountTransactionRepository.SaveTransaction(model);
return this.CreatedAtRoute(ROUTE_NAME_GET_ITEM, new { id = model.Id }, model);
} catch (Exception e) {
this.logger.LogError(LoggingEvents.POST_ITEM, e, string.Empty, null);
return StatusCode(500);
}
}
}
My client may post either BankAccountTransactionModel1 or BankAccountTransactionModel2 and I would like to use a custom model binder to determine which concrete model to bind based on the value in the property ModelType which is defined on the abstract base class BankAccountTransactionModel.
Thus I have done the following
1) Coded up a simple Model Binder Provider that checks that the type is BankAccountTransactionModel. If this is the case then an instance of BankAccountTransactionModelBinder is returned.
public class BankAccountTransactionModelBinderProvider : IModelBinderProvider {
public IModelBinder GetBinder(ModelBinderProviderContext context) {
if (context == null) throw new ArgumentNullException(nameof(context));
if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType) {
var type1 = context.Metadata.ModelType;
var type2 = typeof(BankAccountTransactionModel);
// some other code here?
// tried this but not sure what to do with it!
foreach (var property in context.Metadata.Properties) {
propertyBinders.Add(property, context.CreateBinder(property));
}
if (type1 == type2) {
return new BankAccountTransactionModelBinder(propertyBinders);
}
}
return null;
}
}
2) Coded up the BankAccountTransactionModel
public class BankAccountTransactionModelBinder : IModelBinder {
private readonly IDictionary<ModelMetadata, IModelBinder> _propertyBinders;
public BankAccountTransactionModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders){
this._propertyBinders = propertyBinders;
}
public Task BindModelAsync(ModelBindingContext bindingContext) {
if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext));
// I would like to be able to read the value of the property
// ModelType like this or in some way...
// This does not work and typeValue is...
var typeValue = bindingContext.ValueProvider.GetValue("ModelType");
// then once I know whether it is a Model1 or Model2 I would like to
// instantiate one and get the values from the body of the Http
// request into the properties of the instance
var model = Activator.CreateInstance(type);
// read the body of the request in some way and set the
// properties of model
var key = some key?
var result = ModelBindingResult.Success(key, model);
// Job done
return Task.FromResult(result);
}
}
3) Lastly I register the provider in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => {
options.ModelBinderProviders.Insert(0, new BankAccountTransactionModelBinderProvider());
options.Filters.Add(typeof (SetUserContextAttribute));
});
The whole thing seems OK in that the provider is actually invoked and the same is the case for the model builder. However, I cannot seem to get anywhere with coding the logic in BindModelAsync of the model binder.
As already stated by the comments in the code, all that I'd like to do in my model binder is to read from the body of the http request and in particular the value of ModelType in my JSON. Then on the bases of that I'd like to instantiate either BankAccountTransactionModel1 or BankAccountTransactionModel and finally assign values to the property of this instance by reading them of the JSON in the body.
I know that this is a only a gross approximation of how it should be done but I would greatly appreciate some help and perhaps example of how this could or has been done.
I have come across examples where the line of code below in the ModelBinder
var typeValue = bindingContext.ValueProvider.GetValue("ModelType");
is supposed to read the value. However, it does not work in my model binder and typeValue is always something like below
typeValue
{}
Culture: {}
FirstValue: null
Length: 0
Values: {}
Results View: Expanding the Results View will enumerate the IEnumerable
I have also noticed that
bindingContext.ValueProvider
Count = 2
[0]: {Microsoft.AspNetCore.Mvc.ModelBinding.RouteValueProvider}
[1]: {Microsoft.AspNetCore.Mvc.ModelBinding.QueryStringValueProvider}
Which probably means that as it is I do not stand a chance to read anything from the body.
Do I perhaps need a "formatter" in the mix in order to get desired result?
Does a reference implementation for a similar custom model binder already exist somewhere so that I can simply use it, perhaps with some simple mods?
Thank you.

MVC 4 custom data annotations read in T4 scaffolding

Can you create custom data annotations for the model that can be read inside the T4 template for the View like property.Scaffold is read? I would like to add data annotation parameters like Scaffold based on which I would build the view.
Thank you
I wrote a blog post on the solution I came up with for MVC5. I'm posting it here for anyone who comes along:
https://johniekarr.wordpress.com/2015/05/16/mvc-5-t4-templates-and-view-model-property-attributes/
Edit: In your entities, decorate property with custom Attribute
namespace CustomViewTemplate.Models
{
[Table("Person")]
public class Person
{
[Key]
public int PersonId { get; set;}
[MaxLength(5)]
public string Salutation { get; set; }
[MaxLength(50)]
public string FirstName { get; set; }
[MaxLength(50)]
public string LastName { get; set; }
[MaxLength(50)]
public string Title { get; set; }
[DataType(DataType.EmailAddress)]
[MaxLength(254)]
public string EmailAddress { get; set; }
[DataType(DataType.MultilineText)]
public string Biography { get; set; }
}
}
With this Custom Attribute
namespace CustomViewTemplate
{
[AttributeUsage(AttributeTargets.Property)]
public class RichTextAttribute : Attribute
{
public RichTextAttribute() { }
}
}
Then create a T4Helper that we'll reference in our template
using System;
namespace CustomViewTemplate
{
public static class T4Helpers
{
public static bool IsRichText(string viewDataTypeName, string propertyName)
{
bool isRichText = false;
Attribute richText = null;
Type typeModel = Type.GetType(viewDataTypeName);
if (typeModel != null)
{
richText = (RichTextAttribute)Attribute.GetCustomAttribute(typeModel.GetProperty(propertyName), typeof(RichTextAttribute));
return richText != null;
}
return isRichText;
}
}
}
So, this is how you do it.
Follow this tutorial on how to create a custom attribute http://origin1tech.wordpress.com/2011/07/20/mvc-data-annotations-and-custom-attributes/
To read this attribute values in the T4 scaffolding templates, first add the template files as described here http://www.hanselman.com/blog/ModifyingTheDefaultCodeGenerationscaffoldingTemplatesInASPNETMVC.aspx
Then, for example, open List.tt from the AddView folder. This template creates the Index view.
Go to the end of the template file and find the definition for class ModelProperty. Add your property value to it ( public string MyAttributeValue { get; set; }
Now go a bit down in the List.tt and find bool Scaffold(PropertyInfo property) method. You will need to add your own attribute property reader. This method, for the above mentioned tutorial, would be:
string OptionalAttributesValueReader(PropertyInfo property){
foreach (object attribute in property.GetCustomAttributes(true)) {
var attr = attribute as OptionalAttributes ;
if (attr != null) {
return attr.style;
}
}
return String.Empty;
}
Then find the method List GetEligibleProperties(Type type) at the bottom of the file. Add your reader to it like this:
...
IsForeignKey = IsForeignKey(prop),
IsReadOnly = prop.GetSetMethod() == null,
Scaffold = Scaffold(prop),
MyAttributeValue = OptionalAttributesValueReader(prop)
When you want to use and read this attribute you can do it like the Scaffold property is used in the List.tt
List<ModelProperty> properties = GetModelProperties(mvcHost.ViewDataType);
foreach (ModelProperty property in properties) {
if (property.MyAttributeValue != String.Empty) {
//read the value
<#= property.MyAttributeValue #>
}
}
Since these classes are defined in my project, I had to add my project dll and namespace to the top of the List.tt:
<## assembly name="C:\myProjectPath\bin\myMVCproject.dll" #>
<## import namespace="myMVCproject.CustomAttributes" #>
If your model changes and you need to find these new changes in the scaffolding, you need to rebuild your project.
Hope anyone looking for the solution will find this useful. Ask if there is anything unclear.
This is how I did it in MVC 5. I did this a long time ago and I may be forgetting stuff, I'm just copy/pasting what I see in my modified templates.
I needed a way to set the order of properties in (for example) the create/edit views or in the list view table. So I created a custom attribute OrderAttribute with an integer property Order.
To access this attribute in the T4 templates I modified the file ModelMetadataFunctions.cs.include.t4. At the top I added one method that retrieves the Order value set in the attribute from a PropertyMetadata object, and another method to simply order a list of PropertyMetadata items by that order:
List<PropertyMetadata> GetOrderedProperties(List<PropertyMetadata> properties, Type modelType) {
return properties.OrderBy<PropertyMetadata, int>(p => GetPropertyOrder(modelType, p)).ToList();
}
int GetPropertyOrder(Type type, PropertyMetadata property) {
var info = type.GetProperty(property.PropertyName);
if (info != null)
{
var attr = info.GetCustomAttribute<OrderAttribute>();
if (attr != null)
{
return attr.Order;
}
}
return int.MaxValue;
}
Finally, in the List template for example, I have added a part where I call the GetOrderedProperties method:
var typeName = Assembly.CreateQualifiedName("AcCtc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", ViewDataTypeName);
var modelType = Type.GetType(typeName);
var properties = ModelMetadata.Properties.Where(p => p.Scaffold && !p.IsPrimaryKey && !p.IsForeignKey && !(p.IsAssociation && GetRelatedModelMetadata(p) == null)).ToList();
properties = GetOrderedProperties(properties, modelType);
foreach (var property in properties)
{
//...
}
Unfortunately I needed the name of the project to be able to create a Type object which I needed to get the attributes from. Not ideal, perhaps you can get it some other way but I couldn't manage it without this string including all the version stuff.

JavaScriptSerializer circular reference when using ScriptIgnore

I have my Entity Framework Entities split out into a separate class library from my web project and data access layer. In my controller I make a call to my repository to get an IEnumerable<RobotDog.Entities.Movie> and then try to serialize into json using JavaScriptSerializer but I get a circular reference even though I'm using the [ScriptIgnore] attribute.
IMPORTANT: Originally I had my entities, data access and web all under one project and I was able to successfully serialize my entites without a circular reference. When I created separate layers that's when I started having problems. I did not change any of the entities.
An example of one of my entities in the RobotDog.Entities namespace:
namespace RobotDog.Entities {
public class Character {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[MaxLength(200)]
public string Name { get; set; }
public virtual Person Person { get; set; }
[ScriptIgnore]
public virtual Movie Movie { get; set; }
}
}
My controller:
namespace RobotDog.Web.Controllers {
public class MoviesController : Controller {
private UnitOfWork _unitOfWork = new UnitOfWork();
[HttpGet]
public ActionResult Index() {
var user = Membership.GetUser(User.Identity.Name);
if(user != null) {
var movies = _unitOfWork.UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey).Select(m => m.Movie);
var serializer = new JavaScriptSerializer();
var json = serializer.Serialize(movies);
return View(json);
}
return View();
}
}
}
My Repository:
namespace RobotDog.DataAccess.Movies {
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class {
internal MovieContext Context;
internal DbSet<TEntity> DbSet;
public Repository(MovieContext context) {
if (context == null)
throw new ArgumentNullException("context");
Context = context;
DbSet = Context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null ) {
IQueryable<TEntity> query = DbSet;
if (predicate != null)
query = query.Where(predicate);
return orderBy != null ? orderBy(query).ToList() : query.ToList();
}
}
}
Maybe kinda late response, but I had similar problem with POCO Classes for Entity Framework Code-Firts. The problem was that may properties were declared as virtual. In this case EF creates proxy class which overrides the virtual property. It seems that ScriptIgnore attribute is not by default applied on overriden properties, unless you use it like this:
[ScriptIgnore(ApplyToOverrides=true)]
Circular object graphs cannot be JSON serialized. And when you give it a second thought it actually makes sense. The correct way to handle this is to use view models. You should never pass your domain entities directly to your views. Always define a view model containing only the necessary properties that you want to be exposed.
I am sure that the client consuming this JSON doesn't care about having this circular object graph. So simply define a view model breaking this circular dependency and including only the properties you need.
Then all you have to do is map your domain model to the view model and pass this view model to a JsonResult (yeah that's another issue in your code - you are manually JSON serializing and writing plumbing code in your controller action instead of delegating this to the framework).
So:
[HttpGet]
public ActionResult Index()
{
var user = Membership.GetUser(User.Identity.Name);
if(user != null)
{
IEnumerable<Movie> movies = _unitOfWork
.UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey)
.Select(m => m.Movie);
IEnumerable<MovieViewModel> moviesVm = ... map the domain model to your view model
return Json(moviesVm, JsonRequestBehavior.AllowGet);
}
// return an empty movies array
var empty = Enumerable.Empty<MovieViewModel>();
return Json(empty, JsonRequestBehavior.AllowGet);
}
The important thing you should be focusing right now on is defining the MovieViewModel class which will contain only the information that you want to expose to the client as JSON. Break all circular references. Feel free to have additional view models that this main view model is referencing in order to map other entities.
And most importantly : never pass your domain models to the view. Always define view models. This way your application is completely independent of the underlying data access technology you are using. You could modify your DAL layer as much as you like without impacting the UI part because this UI is represented by view models.

get parameters from URL in controller constructor

I need to write some code to find an ID in my database of a Project.
Users are coupled to a project and all the projects have a lot of connections to other objects, such as Sessions.
Now I need to check before running any Actions, if the user trying to access the Session, is connected to the same project as the session is connected to.
For this i want to use an [Attribute] on the Actions.
MVC: creating a custom [AuthorizeAttribute] which takes parameters?
This question and answer got me started, but i'm having trouble using the constructor of the controller to get my Project ID
the goal is that i can write some code in each constructor, of all my controllers of objects depending on the Projects, find the project ID, and make it accessible (public), so my [customauthorize] will have access to this project ID to check whether the user has access or not.
My problem:
public class SessionController : Controller {
NASDataContext _db = new NASDataContext();
public SessionController() {
var test = RouteData;
var ses = _db.Sessies.First(q=>q.Ses_ID==1);
}
How do I access my routedata? RouteData is null, HttpContext is null and Request is null.
I need the ID in the url, which is in the routedata...
I would suggest placing this check in the Model rather than the Controller. In the Controller you'll need to decorate each action that requires this check, remember this is going execute code on every action you apply it to so you probably don't want to apply it at Controller level to start with. The simpler approach is to implement the check once in the Model then you have no 'concern' in your Controller for access rights. This will make the testing of this access right check possible as you'll only have the test in one place.
This is what i did now to fix it and i'm quite happy about it.
Module Partial:
public partial class Module {
public string FullName {
get {
return Mod_Code + " " + Mod_Titel;
}
}
public string ShortName {
get {
return Mod_Code;
}
}
public bool IsAccessible() {
return this.Projecten.IsAccessible();
}
}
Projects Partial:
public partial class Projecten {
public string FullName {
get {
if (Proj_Kortenaam == Proj_Naam)
return Proj_Kortenaam;
return Proj_Kortenaam + " " + Proj_Naam;
}
}
public string ShortName {
get {
return Proj_Kortenaam;
}
}
public bool IsAccessible() {
return IsAccessible(HttpContext.Current.User);
}
public bool IsAccessible(IPrincipal user) {
//this code checks if the user can access or not
return MvcApplication.projectToegankelijk(user, this._Proj_ID);
}
}
then in the Modules controller
[NonAction]
public ActionResult noRights() {
ViewData["delError"] = "You have no rights.";
return View("Error");
}
//
// GET: /Modules/Details/5
public ActionResult Details(int id) {
var mod = _db.Modules.First(q => q.Mod_ID == id);
if (mod.IsAccessible()) {
return View(mod);
}
return noRights();
}
I think this works pretty neat :)

Best way to filter domain objects for json output in an ASP.NET MVC application

If I'm rendering a regular view in asp.net mvc the only domain object properties that show up in my page the ones I specifically write out. For example:
<div><%= Customer.FirstName %></div>
However, if I serialize a domain object for json it will include every property. Example:
public JsonResult Customer (int? id)
{
Customer customer = _serviceLayer.GetCustomer (id.Value);
return Json (customer);
}
Since I don't want every Customer property exposed what is the best way to filter the output properties for json in this case? Can you use an include/exclude list like UpdateModel()? Use a proxy class such as public class JsonCustomer? What would you recommend?
I use anonymous types for this:
var customer = from c in serviceLayer.GetCustomers()
where c.Id == id.Value
select new { FirstName = c.FirstName };
This is not just a good idea. Rather, it's protection against the exception that you will get when calling Json() if your object graph contains a circular reference.
You may use the [ScriptIgnore] attribute (in System.Web.Extensions). See http://www.creave.dk/post/2009/10/07/Excluding-properties-from-being-serialized-in-ASPNET-MVC-JsonResult.aspx for an example.
Please use a view model. A view model is an object that the UI uses to represent your domain objects on the screen. Each screen has its own view model.
When you make your view model, which is a DTO, which is a flattened, null-safe projection of domain objects, do not map properties you do not wish to be displayed on the screen.
Serialize the view model, not your domain object.
You could use the Newtonsoft library and [JsonIgnore] attribute for marking properties of your class you don't want to expose. There are other libraries (with possible different property ignore attribute name), I personally prefer this one since it's very flexible in JSON converter extensions etc + it can easily serialize anonymous objects.
public class Customer
{
...
[JsonIgnore]
public string UrlIn { get; set; }
public string FirstName { get; set; }
// following example of a converter, you could write your own as well
[JsonConverter(typeof(Newtonsoft.Json.Converters.JavaScriptDateTimeConverter))]
public DateTime Created { get { return _created; } }
}
In my experience, the JavaScriptSerializer respects some of the XmlSerialization attributes such as XmlIgnore too.
I ran into the same problem and THE ONE OF SOLUTION IS to
Use [ScriptIgnore] atribute .. it will solve the problem.
add system.web.extensions reference and add namespace:
Using System.Web.Script.Serialization.
If you still have questions..Read on..for some detailed explanation..
i have a User class with..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Iesi.Collections.Generic;
using System.Runtime.Serialization;
namespace RAPortal.Core.Entities
{
public class User {
private int _userId;
private string _firstName;
private string _lastName;
private IList < Application > _applications;
private IList < Group > _groups;
private IList < ApplicationRequest > _applicationRequests;
....Properties..
public virtual int UserId {
get { return _userId; }
set { _userId = value; }
}
public virtual string Title {
get { return _title; }
set {
_title = !String.IsNullOrEmpty(value) ? value.ToUpper().Trim() : null;
}
}
public virtual IList < Group > Groups {
get { return _groups; }
set { _groups = value; }
}
public virtual IList < UserPrivilege > UserPrivileges
{
get { return _userPrivileges; }
set { _userPrivileges = value; }
}
public virtual IList < UserRole > UserRoles {
get { return _userRoles; }
set { _userRoles = value;}
}
...so on...
and I have Groups class..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Serialization;
using System.Runtime.Serialization;
namespace RAPortal.Core.Entities {
public class Group {
private int _groupId;
private string _name;
private IList < User > _users;
public virtual int GroupId {
get { return _groupId; }
set { _groupId = value; }
}
public virtual string Name {
get { return _name; }
set {
_name = !String.IsNullOrEmpty(value) ? value.ToUpper().Trim() : null;
}
}
[ScriptIgnore]
public virtual IList < User > Users {
get { return _users; }
set { _users = value; }
}
}
}
Since User is referenced in the groups.. the json think that it is Circular reference and It will throw an exception..so the fix is to add [ScriptIgnore] on top of the User. And add the reference and namespace to this class like it..
It solved my problem .. I am sure there are better ways out there !!! Cheers...
And remember you should add [scriptIgnore] only in the groups class and not in the Users class..

Resources