My questions is: I have an enum class as:
public enum EnumApplications
{
Android = 1,
IOS = 2
}
Also I have a Model which is for Creating a new user. a user can be defined as Active in any of these application when we create a new user.
My model is:
public class NewUserModel
{
public int UserId { get; set; }
[Required]
[Display(Name = "FirstName")]
public string FirstName { get; set; }
[Required]
[Display(Name = "LastName")]
public string LastName { get; set; }
public int ClientId { get; set; }
[Required]
[Display(Name = "Email")]
[EmailAddress]
public string EmailAddress { get; set; }
[Display(Name = "Is Active in IOS")]
public bool IsActiveInApp1 { get; set; }
[Display(Name = "Is Active in Android")]
public bool IsActiveInApp2 { get; set; }
}
What I want to do is in the: [Display(Name = "Is Active in Android")]
I want to use the enum so if the app name gets changed I don't need to change it here, something like:
EnumApplications.IOS.ToString()
Here's a screenshot for better understanding:
"I want to use the enum so if the app name gets changed I don't need to change it here"
No, there is no easy way to do this.
the only implementation I can think of (aside from runtime assembly/type compiling and generation) that you could do that, is a T4 template. the template would generate the model, and you would have to run it after modifying your enum.
in regards to your question title and comment:
MVC - Using Enum In The DisplayAttribute of a Model class
what I want is in my model instead of saying [Display(Name = "Is Active in IOS")] and hardcoding IOS. I want to get the name of IOS from my enum.
The following solution (which isn't T4 or Runtime compiling) just inherits DisplayNameAttribute and uses the constructor of your type to pass the parameter to the base type.
It is a solution in the sense that if you were to change Android to Andy you would use a refactor tool ( built-in intellisense tool these days) to implement that change across code files that references that value type.
public enum MyEnum
{
NotSet = 0,
iOS = 1,
Android = 2
}
class MyDisplayNameAttribute : System.ComponentModel.DisplayNameAttribute
{
public MyDisplayNameAttribute(MyEnum myEnum)
: base("Is Active in " + myEnum.ToString())
{
}
public override string DisplayName
{
get
{
// you could do the "Is Active in " here, but I doubt control frameworks would use it.
return base.DisplayName;
}
}
}
public class MyModel
{
[MyDisplayName(MyEnum.iOS)]
bool IsActiveApp1 { get; set; }
// uses standard 'DisplayNameAttribute' type for test below
[System.ComponentModel.DisplayName("Is Active in Android")]
bool IsActiveApp2 { get; set; }
}
For quick testing, we'll do what control frameworks do, reflect over the provided type and get the CustomAttribute.. note that there is more type checking involved, we'll casting it to DisplayNameAttribute for brevity.
string[] PropertyNames = new string[] { "IsActiveApp1", "IsActiveApp2" };
System.Type MyModelInfo = typeof(MyModel);
PropertyNames.SelectMany(prop => MyModelInfo.GetProperty(prop).GetCustomAttributes(true))
.ToList().ForEach((attr) =>
{
Console.WriteLine(((System.ComponentModel.DisplayNameAttribute)attr).DisplayName);
});
Related
I have a few EF model classes that I want to create. Each class has a few common properties that I want to set before inserting a new entity, for example:
public partial class BlogPost {
public DateTime CreatedTime { get; set; }
public string CreatorName { get; set; }
public string PostTitle { get; set; }
public string PostText { get; set; }
}
public partial class Comment {
public DateTime CreatedTime { get; set; }
public string CreatorName { get; set; }
public string CommentText { get; set; }
}
...
When I create these classes, I'm instantiating them like so:
var blogPost = new BlogPost {
CreatedTime = DateTime.UtcNow,
CreatorName = creatorName,
PostTitle = postTitle,
PostText = postText,
};
var comment = new Comment {
CreatedTime = DateTime.UtcNow,
CreatorName = creatorName,
...
};
...
I want to create a method to automatically set some of the common properties so I don't need to manually type them out for each class with the same properties. Since they don't extend the same class or implement the same interface, I'm wondering how this can be achieved. My first thought was to use a generic method; however, I don't know if there's a way to specify what properties the generic type should have without them extending the same class (similar to TypeScript's "duck typing"). My desired method looks something like this:
public void SetInitialProperties<T>(T dbEntity, DateTime createdTime, string creatorName) where T : ??? {
dbEntity.CreatedTime = createdTime;
dbEntity.CreatorName = creatorName;
}
...
var blogPost = new BlogPost { PostTitle = postTitle, PostText = postText };
SetInitialProperties(blogPost, createdTime, creatorName);
Worst case scenario if I can't use a generic, I could always use dynamic; however, I'd like to keep type checking if possible.
You can achieve what you want using reflection. You can pass in an object and resolve it's type, then get all the public properties of that given type and find if you have one called CreatedTime for example. Then you can set the value of the given property on the passed dbEntity object. However, I do not recommend this solution:
public void SetInitialProperties(object dbEntity, DateTime createdTime, string creatorName) {
// get the passed object's properties and find the one called CreatedTime
var createdTimePropertyInfo = dbEntity.GetType().GetProperties().Where(i => i.Name == "CreatedTime").FirstOrDefault();
// below line is equal to: dbEntity.CreatedTime = createdTime;
createdTimePropertyInfo.SetValue(dbEntity, createdTime);
var creatorNamePropertyInfo = dbEntity.GetType().GetProperties().Where(i => i.Name == "CreatorName").FirstOrDefault();
creatorNamePropertyInfo.SetValue(dbEntity, creatorName);
}
You would be better off on the long run by creating a common interface or even an abstract base class so you don't have to implement CreatedTime and CreatorName and other properties for every EF model. It would look like the following:
public interface IUserEntry
{
DateTime CreatedTime { get; set; }
string CreatorName { get; set; }
}
public abstract class UserEntryBase : IUserEntry
{
public DateTime CreatedTime { get; set; }
public string CreatorName { get; set; }
}
public partial class BlogPost : UserEntryBase
{
public string PostTitle { get; set; }
public string PostText { get; set; }
}
public partial class Comment : UserEntryBase
{
public string CommentText { get; set; }
}
And your SetInitialProperties would be pretty simple:
public void SetInitialProperties(IUserEntry dbEntity, DateTime createdTime, string creatorName)
{
dbEntity.CreatedTime = createdTime;
dbEntity.CreatorName = creatorName;
}
Once you develop onto an interface, you achieve much more flexibility than by using reflection or a dynamic type, since you get the compile-time checking that was mentioned before me and you can see the common properties of your models.
You can't do that in C# because C# uses a nominal type system and not a structural type system.
For your particular case you have to come up with an interface that contains the properties in common and which will be implemented by both entities, then use that new interface as you generic function parameter constraint.
If you're absolutely sure the properties will have the same name, you could pass a dynamic to set property values. However, this prevents any compile-time checking of the typing, so if you accidently pass an incompatible type it won't be caught until runtime.
public void SetInitialProperties(dynamic dbEntity, DateTime createdTime, string creatorName) {
dbEntity.CreatedTime = createdTime;
dbEntity.CreatorName = creatorName;
}
I have created a class and I'm putting a list of same type as a property of that class.
Is it good or bad practice?
I am putting the same type of list because of I want to manage everything by only one object.
I don't want to create a single object and a list of object of the same type.
Any help is highly appreciated!
class AssetSection
{
public string Code { get; set; }
public string Description { get; set; }
public string SITEID { get; set; }
public string PlantID { get; set; }
public string User { get; set; }
public string UpDateTime { get; set; }
public List<AssetSection> AssetSections { get; set; }
public AssetSection(string des, string code)
{
Description = des;
Code = code;
}
}
That's ok. If you can imagine, you can design and use it.
Let's talk about entity framework. We create 2 entities like this:
public class User : IdentityUser
{
[Key]
public string Id { get; set; }
public UserProfile Profile { get; set; }
}
public class UserProfile
{
[Key]
public string UserId { get; set; }
public User User { get; set; }
}
Now, when we try to get current user:
User user = await _userManager.GetUserAsync(User);
user becomes an instance of User class now. This instance has a property name Profile, and this property has another property name User which has a type User.
It's called mapping. So, to answer your question: You can use it. But I'm not saying it's good or not based on the way to design the model.
As a general observation, such a structure is known as a rose tree, or just a tree. It enables you to write code like this:
var t = new AssetSection("foo", "bar")
{
AssetSections = new List<AssetSection>
{
new AssetSection("baz", "qux")
{
new AssetSection("corge", "garply"),
new AssetSection("fred", "plugh")
{
AssetSections = new List<AssetSection>
{
new AssetSection("xyzzy", "thud")
}
}
},
new AssetSection("quux", "quuz")
{
new AssetSection("grault", "waldo")
}
}
};
If what you want to model is a tree-like structure like that, then it's fine. On the other hand, if such a hierarchy is not what you're trying to model, then it's likely to be confusing.
By the way, the code as proposed violates the .NET framework design guidelines:
DO NOT provide settable collection properties.
DO NOT use ArrayList or List<T> in public APIs
The issue:
Entity object has it properties related to databases on its own, but the needs in the programming area is differ, sometimes we want to add it some more:
Properties – that is for temporary logic.
Methods – for clean code and for programming necessaries.
Finally yet importantly – Attribute for authorization, display, filters etc.
However, obviously we do not want our program to be maintainability without needs to rewrite code just after we update the model.
For properties and methods, the Entity Framework platform generated all the object from model as partial classes and the .NET environment allow us to extend them as we wish:
Remember to check that our partial sit in same namespaces (Notice that when we create them in model directory or in them own directory Visual Studio create addition namespace).
public partial class ErrorLog
{
public long pk { get; set; }
public int lineNumber { get; set; }
public Nullable<int> error { get; set; }
}
Our partial:
public partial class ErrorLog
{
public string getErrorDescription()
{
return d[(int)error];
}
private static Dictionary<int, string> d = new Dictionary<int, string>()
{
{1,"desc1" },
{2,"desc2" },
{3,"desc3" },
{4,"desc4" }
};
}
For attributes:
We can add new interface
public interface IErrorLogsMetaData
{
[Display(Name = "Id")]
long pk { get; set; }
[Display(Name = "The line Number")]
int lineNumber { get; set; }
[Display(Name = "The Error")]
Nullable<int> error { get; set; }
}
Implement them on our Entity (even extended) object.
For that we need to reflect and book it in global.asax by using:
TypeDescriptor.AddProviderTransparent(
new AssociatedMetadataTypeTypeDescriptionProvider(typeof(ErrorLog), typeof(IErrorLogsMetaData)), typeof(ErrorLog));
TypeDescriptor – familiar for us from reflection, its get information about type.
AddProviderTransparent – is the method called from my partially trusted code and get metadata from associated class.
The first parameter is the provider and it TypeDescriptionProvider from the type we want to decorate and the attributed interface, the second parameter is the target type for decription.
Another Option
Make your partial view to implement the IErrorLogsMetaData and then you don't need to associate at Global.asax
As you can see, the database first entity model classes are partial, so you can create your own partial class, for example if you have:
public partial class SomeClass
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
You can do something like this:
Add some class to your project, name it SomeClassPartial:
//SomeClassPartial.cs
namespace YourNamespace
{
[MetadataType(typeof(SomeClassMetadata))]
public partial class SomeClass
{
//add your new properties/some_logic here
public string NewPropX { get; set; }
public string NewPropY { get; set; }
}
public partial class SomeClassMetadata
{
//metadata for your existing model properties
[Display(Name = "Property 1")]
public string Prop1 { get; set; }
[Display(Name = "Property 2")]
public string Prop2 { get; set; }
}
}
In your SomeClassMetadata class you can add data annotation attributes to your existing properties with MetadataType attribute, which will specify the metadata class to associate with a data model class, and with that you can tell you partial SomeClass class to get that attributes from SomeClassMetadata class. To add new custom properties, you can use SomeClass partial class.
MSDN Link: MetadataTypeAttribute Class
I'm looking for a simpler/drier way to use ressources my MVC 3 models.
This is how I'm doing it now (Each attribute needs to be told which ressource type it uses):
public class ContactMessageModel:BaseModel
{
[Display(Name="ReplyToEmail_DisplayName", ResourceType = typeof(Res.Views_Contact))]
public string ReplyToEmail {get; set; }
[Display(Name = "ContactReason_DisplayName", ResourceType = typeof(Res.Views_Contact))]
public string ContactReason { get; set; }
Can this be done?
This is how I'd like to do it (I just want to define the resource type for the model once):
[Display(ResourceType = typeof(Res.Views_Contact))]
public class ContactMessageModel:BaseModel
{
[Display(Name="ReplyToEmail_DisplayName")]
public string ReplyToEmail {get; set; }
[Display(Name = "ContactReason_DisplayName")]
public string ContactReason { get; set; }
Doesn't seem possible, because the attribute instance would require access to the property it is sitting on, which .NET does not support.
Yes, defaulting the ResourceType can be done. Phil Haack shows an example of how to override .NET's ModelMetadataProviders to accomplish this and prevent having to repeat yourself specifying the same ResourceType over and over:
http://haacked.com/archive/2011/07/14/model-metadata-and-validation-localization-using-conventions.aspx/
You can either default to a single ResourceType globally, or decorate specific classes with a default using this attribute he defines:
public class MetadataConventionsAttribute : Attribute
{
public Type ResourceType { get; set; }
}
I need to validate two fields only if a third field has a specific value.
In this code snipper i suppose to use a CheckIf properties that not exist.
It is possible to validate a field only if another property hase a specifica value ?
public string CustomerType { get; set; } // P=Private B=Business
[NotNullValidator(MessageTemplate = "You must specify the property 'Name'", CheckIf = "CustomerType=='P'")]
public string PrivateName { get; set; }
[NotNullValidator(MessageTemplate = "You must specify the property 'Name'", CheckIf = "CustomerType=='B'")]
public string BusinessName { get; set; }
Thank you!!!
From a validation perspective I agree with Siva that you can use SelfValidation for this. When looking at your code however, from an OO perspective, I can't help noticing that it might be good to take a good look at your design. It seems that either you are showing us two sub types of Customer, namely PrivateCustomer and BusinessCustomer:
class Customer
{
}
class PrivateCustomer : Customer
{
public string PrivateName { get; set; }
}
class BusinessCustomer : Customer
{
public string BusinessName { get; set; }
}
Or... those two properties are actually the same thing. Your validation messages even calls them 'Name' in both cases. In that case, you'll end up with this design:
class Customer : Customer
{
public string CustomerType { get; set; }
public string Name { get; set; }
}