I'm trying to dynamically assign a value from DB to a property which inherits from EpiServer PageData class. Here is what I mean:
namespace Episerver9.Models.Pages
{
[ContentType]
public class StartPage : PageData
{
public virtual string Username { get; set; }
public virtual string Password { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
[ReadOnly(false)]
[Editable(true)]
public virtual string testfield { get; set; }
}
}
And in controller I'm trying the following:
namespace Episerver9.Controllers
{
public class StartPageController : PageController<StartPage>
{
// GET: StartPage
public ActionResult Index(StartPage currentPage)
{
currentPage.testfield = "test";
return View(currentPage);
}
}
}
And this is what I'm trying to display in the view:
#Html.PropertyFor(x=>x.testfield)
// Trying to dynamically populate the data from code, later on from DB
The error that I'm getting is:
Additional information: The property testfield is read-only
This happens even tho I clearly specified for the property that IT IS NOT read only... Does anyone knows why?
This is because ContentData objects are always read-only for performance purposes. To change any properties, you have to create a writable clone like:
currentPage.CreateWritableClone()
That will give you an instance of your page that you can change, for example to save changes using an IContentRepository instance.
However, note that these instances are read-only for a reason. :) You're better off creating a separate view model that you pass to your view.
Related
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
i am having around 7 models who have same properties(atributes). On view page i am using a model(name = commonModel) which contains all those properties and a extra property to choose in which model's database i want to save that sent data so i created a valuesRelocate Method that will assign all the properties of commonModel to the choosen model (in this case article).
The code i gave below is working but i am getting a error when assigning value of a property of commonModel to a property of article.
What is the better way to do this.
Error is at tempModel.question
public ActionResult Create([Bind(Include =
"Id,question,ans,ruleApplicable,hint,exception,modelSelector")]
commonModel commonModel)
{
if (ModelState.IsValid)
{
if (commonModel.modelSelector == "article")
{
article model2 = new article();
article model1 = valuesRelocate<article>(commonModel,
model2);
db.articleDb.Add(model1);
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(commonModel);
}
private T valuesRelocate<T>(commonModel commonModel, T tempModel) {
tempModel.question = commonModel.question;
return tempModel;
}
I am using a abstract base class named baseGrammar .code for both the class is shown below
public abstract class baseGrammar
{
[Key]
public int Id { get; set; }
[Required]
public string question { get; set; }
[Required]
public string ans { get; set; }
public string ruleApplicable { get; set; }
public string hint { get; set; }
public bool exception { get; set; }
}
the one shown above is base class
and those shown below are derived classes
i use different classes because i wanted to have different classes for different grammatical concepts.
public class article : baseGrammar
{
}
public class commonModel : baseGrammar
{
[Required]
public string modelSelector { get; set; }
}
hope this helps.
You just need to constrain the type parameter T to be derived from your base class:
// Names changed to follow .NET naming conventions
private T RelocateValues<T>(BaseGrammar baseModel, T tempModel)
where T : BaseGrammar
{
tempModel.question = baseModel.question;
return tempModel;
}
However, given that you're modifying the incoming model, you could remove the return value and just change the method to:
private void RelocateValues(BaseGrammar from, BaseGrammar to)
{
to.question = from.question;
}
Then in your calling code:
Article model = new Article();
RelocateValues(model);
db.ArticleDb.Add(model);
There's no need to have two separate variables which will refer to the same object anyway...
I'm bulding a WPF application on visual studio 2013 with Entity-Framework (Code First).
I have a Order class, that has a virtual property for Customer.
public class Order
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set;}
public virtual Customer Customer { get; set; }
}
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public string DocumentNumber { get; set; }
public DateTime BirthDate { get; set; }
}
I'm trying to show the customer's name on report formula. I've tried:
=First(Fields!Customer.Value.Name, "MyDataSet")
=First(Fields!Customer.Name.Value, "MyDataSet")
and
=Fields!Customer.Value.Name
=Fields!Customer.Name.Value
It just shows #Error on that field. Other fields from Order are displayed properly.
It works:
=First(Fields!OrderDate.Value, "MyDataSet")
I loaded the Customer by using Include when I retrieve the entity from context. So a null reference is not the problem.
Order order = context.Orders.Include(o => o.Customer).Where(o => o.OrderID == id).FirstOrDefault();
I searched the following and others, but sounds like is just for visual studio 2010 or just didn't work:
Bind child object property with in rdlc (Report)
http://wraithnath.blogspot.com.br/2011/04/reportviewer-object-datasource-nested.html
Is there some thing I didn't do or I should work another way on that, like some kind of "code-first-view"?
This answer worked for me in VS2013:
http://wraithnath.blogspot.com/2011/04/reportviewer-object-datasource-nested.html
Be sure you classess fullfill with the requirements, remember add the parameterless constructor, (it only worked for me until i added the parameterless constructor)
Checklist:
ALL classes are serializable (every user type in the class must be
serializable, and any user type in a property of a usertype must be
serialzable)
ALL classes have a public parameterless constructor
ALLclasses used in the report must have the public modifier
If any property of the datasource, or any property of a property cannot be
serialized then your will get the #Error. Just make sure everything
is serializable
Make sure there will be no infinite recursion issues eg, class A has a
property of class B, and class B has a property of class A. Use XMLIgnore / ScriptIgnore attributes
This are my classes:
[Serializable]
public class Person
{
public Person()
{
}
public string Name{ get; set; }
public string Address1{ get; set; }
public string Id{ get; set; }
public string Phone { get; set; }
}
Parent:
[Serializable]
public class Header
{
public Header()
{
}
public string Product { get; set; }
public DateTime EmisionDate{ get; set; }
public string Number { get; set; }
public Person Person { get; set; }
}
And this is my expression
=First(Fields!Person.Value.Name, "dsHeader")
I'm not sure if this is the accepted standard for doing this kind of thing but what I've found to be the most reliable. (VS Rdlc work is bugged to hell and not well documented in the wpf realm)
So you have your dataset for your 'Order' object which contains the customer object you're trying to access properties from. Now, create another dataset of the 'Customer' object.
Then in code, populate your 'Order' object with everything as you normally would and then set the second dataset's binding source we created based on your 'Customer' object to the 'Customer' object that is inside your 'Order' object
Order order = new Order();
order.OrderId = 1;
order.OrderDate = DateTime.Now;
order.Customer = new Customer("John", "Shmoe");
OrderBindingDataSet.DataSource = order;
CustomerBindingDataSet.DataSource = order.Customer;
Hope this helps, I know from personal experience how irritating it is to have to use this piece of work along with it having little to no documentation for these kind of things. :)
I've often found myself fixing validations for the modelstate manually, due to the inconsistency of some fields that are required in a view model during post and get.
Supposing I've got this View Model:
public class RestaurantMenuName_ViewModel
{
public Int64 RestaurantMenuNameId { get; set; }
public Int64 OwnerId{ get; set; }
public string MenuNameCategory { get; set; }
public string CategoryDescription { get; set; }
public bool IsFormSaved { get; set; }
}
During a GET request the controller/Action requires the validation of just the fields, RestaurantMenuNameId and OwnerId. When calling the Action RestaurantMenuName, the query string values are RestaurantMenuNameId and OwnerId. Modelstate validation will be done on:
RestaurantMenuNameId
OwnerId
During a POST request the controller/Action will require the modelstate validation of the fields:
RestaurantMenuNameId
OwnerId
MenuNameCategory
CategoryDescription
This is the inconsistency issue I'm talking about, a solution could be using a ViewModel for Get requests and one for Post, but this could be real a time waster and error prone. Using ViewBag is out of discussion.
Question:
Is there a way to tell MVC that we want some fields [required] for GET and other for POST?
The following is a Pseudo-code of what I'm talking about:
public class RestaurantMenuName_ViewModel
{
[Required: in GET, POST] //<--Pseudo code
public Int64 RestaurantMenuNameId { get; set; }
[Required: in GET, POST] //<--Pseudo code
public Int64 OwnerId { get; set; }
[Required: in POST] //<--Pseudo code
public string MenuNameCategory { get; set; }
[Required: in POST] //<--Pseudo code
public string CategoryDescription { get; set; }
public bool IsFormSaved { get; set; }
}
It's not a very good practice (and confusing in your case) to pass complex objects when you need only few properties. It will be better to pass only the required ids as primitives.
If the case is special and you really need the complex objects, it will be better to create two different view models for every request and decorate the required properties accordingly.
However, you can create your own require validation attribute which will validate properties dependening on the current request.
public class MyRequiredAttribute : ValidationAttribute
{
private string httpVerb;
public MyRequiredAttribute(string httpVerb)
{
this.httpVerb = httpVerb;
}
public override bool IsValid(object value)
{
if(HttpContext.Current.Request.HttpMethod == this.httpVerb)
{
return value != null;
}
return true;
}
}
// Usage
public class MyViewModel
{
[MyRequired("GET")]
public string A { get; set; }
[MyRequired("POST")]
public string B { get; set; }
}
Note: you can use an enumeration to avoid some difficulties (ex. upper case, lower case, misspelling etc.) and also you can override the FormatErrorMessage method to change the default error message and format it properly.
I'm sorry if it's a dumb question, but i just can't seem to get a grip.
I got 2 classes, Customer and Member.
Customer.cs
public class Customer
{
public virtual string Firstname { get; set; }
public virtual string Middlename { get; set; }
public virtual string Lastname { get; set; }
}
Member.cs
public class Member : Customer
{
public virtual string MemberId { get; set; }
public virtual string MemberRegistrationDate { get; set; }
public virtual string MembershipStatus { get; set; }
public Member()
{
MemberRegistrationDate = DateTime.Now;
MembershipStatus = MembershipStatusEnum.Active;
}
}
I'm pretty sure this has to be an inheritance, in which Member is a Customer, though if I'm being desperate I can resort to composition.
Note that here I'm using NHibernate that forces me to use all that virtuals.
Given a single customer object, how should a new Member from an existing Customer ?
I can think of 2 options here :
1 - Using Member.cs constructors to recreate it's parents properties
Is this a good thing to do? I tried to do this :
public class Member : Customer
{
public virtual string MemberId { get; set; }
public virtual string MemberRegistrationDate { get; set; }
public virtual string MembershipStatus { get; set; }
public Member(Customer customer)
{
Firstname = customer.Firstname;
Middlename = customer.Middlename;
Lastname = customer.Lastname;
MemberRegistrationDate = DateTime.Now;
MembershipStatus = MembershipStatusEnum.Active;
}
}
But Resharper warns me about accessing virtual member in a constructor, which I do agree to avoid, and tells me to make Member a sealed class which cannot have virtual members (no NHibernate compatibility).
It also raises another issue when someday I added a new property to Customer class, and I forgot to do the same to Member constructor.
2 - Using some sort of reflection helper to map between two objects.
Sure it's a viable option, but I'm currently learning about DDD and I'm wondering if it's okay to put such helper in the domain layer?
Need some suggestions, thanks !
Not sure if I get you right, but there's no need to do anything Customer related in your Member class. You only need to tell NHibernate that Member derives from Customer, and you need to provide the correct mapping for both classes. That's it, the rest goes automatically (that's the whole point of inheritance in OOP, anyway).
Regarding your second issue ('Don't call virtuals in c'tor.'): That's theoretically true, but only relevant if there's a chance that the virtual method gets overwritten in a derived class. So you could safely ignore the R# warning here.
But I think it's cleanest here to get rid of the Member c'tor altogether and declare the class like so:
public class Member : Customer
{
private memberRegistrationDate = DateTime.Now;
private membershipStatus = MembershipStatusEnum.Active;
public virtual string MemberId { get; set; }
public virtual string MemberRegistrationDate
{
get { return this.memberRegistrationDate; };
set { this.memberRegistrationDate = value; };
}
public virtual string MembershipStatus
{
get { return this.membershipStatus; };
set { this.membershipStatus = value; };
}
}
EDIT:
If you're looking for an easy way to turn a customer, into a member, you should maybe entirely keep the conversion code away from your classes and put it into an extension method instead (to keep things clean):
public static class CustomerExtensions
{
public static Member ToMember(this Customer customer)
{
var member = new Member();
member.Firstname = customer.Firstname;
member.Middlename = customer.Middlename;
member.Lastname = customer.Lastname;
return member;
}
}
You can call it then like this:
Member member = customer.ToMember();