Can not create instance of an inherited class from an abstract class - c#

I have a class inherited from an abstarct class. On razor, when I create instance of child class, I got this error as is shown in image:
Cannot create an abstract class
But StuffRegisterSearchParameterVM is not an abstract class. Why this happen?
Controller
public ActionResult SearchRegistration(SearchParameterVM model)
Model
abstract public class SearchParameterVM
{
public string FromDate { get; set; }
public string ToDate { get; set; }
public int? MainTestRegisterId { get; set; }
public int TestTypeId { get; set; }
public bool IsForAnsweringPage { get; set; }
}
public class StuffRegisterSearchParameterVM : SearchParameterVM
{
public int? StuffId { get; set; }
public string Code { get; set; }
}

You can not use abstract class as a parameter of action, because asp.net mvc does not know anything abount posted object type, it trys to create an argument type, and this type is abstract.
So, replace it this concrete class or create special binder.

When you define the action:
public ActionResult SearchRegistration(SearchParameterVM model)
That defines a method that MVC will call based on your routes when an http request is made to the server. That http request probably contains only parameters like you would have if you had a web form. MVC model binding simply creates an instance of the class specified in the parameter to the action in C# and tries to set the property values based on the http parameters passed in the http call. This call could be from a view action like you have, from a static html page, from a program, or anywhere else you can make an http call. When it is an abstract class, it cannot create an instance of it.If you had 3 child classes based on your abstract class, MVC would have no way to tell which type to create.
You can check out this question for some more information.
So how would you determine what concrete class should exist in memory when a call to that action is made, given only parameter names with different values? You could create different routes and actions that had different types in their parameters. You could also check those parameters and create different concrete classes based on the passed parameters. For instance if you wanted to use a certain class based on if the 'code' value is passed, , you'll either have to create your own IModelBinder which could determine which concrete class based on the passed query parameters:
public class MyModelBinder : IModelBinder {
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
// create different concrete instance based on parameters
ValueProviderResult code = bindingContext.ValueProvider.GetValue("Code");
if (code.AttemptedValue != null) {
// code is passed as a parameter, might be our class
// create instance of StuffRegisterSearchParameterVM and return it
}
// no Code parameter passed, check for others
}
}
Then you have to tell in your startup that you have a special model binder
for your abstract class:
ModelBinders.Binders.Add(typeof(SearchParameterVM), new MyModelBinder());
Or you could do something in your action to determine what type to create and use TryUpdateModel to set the values:
public ActionResult SearchRegistration() {
SearchParameterVM model = null;
if (Request.Parameters["code"] != null) {
model = new StuffRegisterSearchParameterVM();
TryUpdateModel(model); // check return value
}
}

Related

C# - Call a derived base method in the derived context

Tried to search the web but found nothing so far so here my question:
I want to index model-information via attributes on the different members.
To do this i created a function in a base class that gathers all needed information when called.
This method is derived into the different models so that they can all be indexed.
Base()
{
public virtual void Index() {...}
}
In the base class I'm calling a generic method that gives me acces to the indexing server for the specific model that I want to save there
using (var indexFacade = IndexFacadeFactory.GetIndexFacade(configuration, this))
{
indexFacade.Execute(this, operation);
}
The issue I'm currently having is that when calling the factory it retrieves the information for the base-class.
What I want to acomplish is something like this:
Derived : Base
{
[IndexingKey]
long Id { get; set; }
[IndexingField]
string SomeValue { get; set; }
}
var derived = new Derived();
derived.Index();
My indexFacade holds the type of
IndexFacadeBase<Base>
I'm aware of the polimorphism here and why this happens.
My question is:
How can i call
derived.Index();
so that the context from which it is called is not from the base-class without overwriting it?
Further information:
The method that is called looks like this:
public static IndexFacadeBase<T> GetIndexFacade<T>(IndexInfo.IndexConfiguration config, T model)
{
IndexFacadeBase<T> retVal;
.....
return retVal;
}
The T has the type of Base.
The model has the type of Derived.
Maybe that clears up some of the Problems.
I get back:
IndexFacadeBase<Base>
I would need back:
IndexFacadeBase<Derived>
Thanks in advance for all the help.
I may not be fully understanding your question, but aren't you simply looking to override the method in the derived class?
class Base
{
public virtual void Index() { }
}
class Derived : Base
{
public override void Index() { } // here is the override.
long Id { get; set; }
string SomeValue { get; set; }
}
Then when you do this:
var derived = new Derived();
derived.Index();
The derived class' Index method is called.
Maybe it would work if your IndexFacadeBase<Base> was changed to IndexFacadeBase<T> where T:Base.

How do I get only a shadowed property, not the base property, to get JSON serialized?

In my ASP.NET MVC web application, I am using the built in Controller.Json() method to serialize an object and send it back to the client in response to an AJAX call. The class of the object being serialized inherits from another class with some shared property names. This is intentional, as I need the property names to match for some reflection that's happening. I am "shadowing" those properties in the derived class so that they can be a different type from their same-name counterpart in the base class. Here's a simplified example:
public class BaseModel
{
public string Title { get; set; }
public decimal CleanUpHours { get; set; }
public decimal InstallHours { get; set; }
}
public class DerivedModel : BaseModel
{
public new BucketHoursWithCalculations CleanUpHours { get; set; }
public new BucketHoursWithCalculations InstallHours { get; set; }
}
When I serialize an instance of DerivedModel, my JSON object on the client contains only the decimal versions of CleanUpHours and InstallHours, not my custom class BucketHoursWithCalculations.
Inspecting the object in Visual Studio before it gets serialized shows both the base and derived versions of those properties, as shown here (please excuse all the extra properties — my sample classes above are more simplified than what I'm actually using, but the principle is the same):
Here's what that object looks like on the client once it's serialized into JSON:
As you can see, the derived/shadowed properties were not serialized, and the base properties were, but only in the cases where there was a name conflict (for example, the Title property in the base model serialized just fine).
How can I serialize only the shadowed properties where there's a name conflict? I don't believe changing the access modifiers (i.e. from public to protected or something) on the base properties will work in my case, because the BaseModel is used by Entity Framework, and must have public properties. Any help would be appreciated.
One idea is to define type parameter on the base model that is used for the hours properties. Then, define derived models for decimal and BucketHoursWithCalculations. I would be interested to see how BucketHoursWithCalculations serializes to JSON, but in any case the CleanUpHours and InstallHours properties should be serialized.
// use a type parameter on the base model that must be specified
// in derived models.
public class BaseModel<THours>
{
public string Title { get; set; }
public THours CleanUpHours { get; set; }
public THours InstallHours { get; set; }
}
// hours are specified as decimals
public class DecimalModel : BaseModel<decimal>
{
}
// hours are specified as BucketHoursWithCalculations
public class BucketHoursWithCalculationsModel : BaseModel<BucketHoursWithCalculations>
{
}
// usage
DecimalModel d = new DecimalModel();
d.CleanUpHours = 1.0M; // CleanUpHours is a decimal here
BucketHoursWithCalculationsModel b = new BucketHoursWithCalculationsModel();
b.CleanUpHours = new BucketHoursWithCalculations();
b.CleanUpHours.SomeProperty = 1.0M;

Model binding to an inheriting class

I have the following classes:
public abstract class InputVariableVm
{
public InputVariableVmType Type { get; set; }
}
[KnownType(typeof(BoolInputVariableVm))]
public class BoolInputVariableVm : InputVariableVm
{
public bool Value { get; set; }
public BoolInputVariableVm(string name, bool value)
{
Value = value;
Type = InputVariableVmType.Bool;
}
}
[KnownType(typeof(StringInputVariableVm))]
public class StringInputVariableVm : InputVariableVm
{
public string Value { get; set; }
public StringInputVariableVm(string name, string value)
{
Value = value;
Type = InputVariableVmType.String;
}
}
In my Web API controller I'm trying to bind to an object of InputVariableVm (String or Bool).
However the object is always null - but when I remove the "abstract" keyword from the base class it inserts the base class (but without the concrete implementation, thus missing the Value property).
What could be the cause of this?
By the way, I'm well aware that writing a custom model binder would solve this but I would like to avoid doing this if possible.
This is just how the default model binder works - the type you put as the action parameter is the type the binder will attempt to instantiate, it has no idea that really you want a derived type instantiated behind the scenes. FWIW the reason it's null in the first scenario is because you can't instantiate an abstract class hence why removing it then works.
By the way, I'm well aware that writing a custom model binder would solve this but I would like to avoid doing this if possible.
Unfortunately, there is no way around it - you are going to need a custom model binder.

Pass Json object as object of type System.Object or Interface not working

Class:
public class ClassNameA :ISomeInterface {
}
public class ClassNameB :ISomeInterface {
}
From javascript:
var reqP = { 'Id': id, 'Name':name };
var ReqParams = { 'ReqParams': reqP };
var obj = { 'ClassNameA': ReqParams };
makeAjaxCall("POST",
JSON.stringify(obj), '/ControllerName/someMethod/', 'html',
Action method looks like:
public ActionResult someMethod(object obj){
// call comes to this method but obj is not populated.
}
public ActionResult someMethod(ISomeInterface obj){
// call comes to this method but throws exception.
// Exception : Cannot instantiate interface. but i am passing class object.
}
from JavaScript I will pass object of a concrete class type which implements ISomeInterface so that I can have multiple implementations. Concrete Class can of any one of the two types.
Any Suggestions?
That won't work. The model binder needs a concrete type to be able to create an instance and bind the values.
object is a concrete type and can be created using Activator.CreateInstance, but it doesn't have any properties that will match the data you receive.
The interface (or abstract types) cannot be created, since they're not concrete types. It's a simple as that.
If the JSON contained some hint about the type, it migth be possible to implement a custom model binder to create the instances for you. You can read more about the model binding process here.
The default model binder is not going to be able to figure out what to do. Let's just go through the exercise with some sample interfaces to show why. Say you have this:
public ActionResult SomeMethod(ISomeInterface obj)
{
// ...
}
...and say you have these two implemenetations:
class ClassA : ISomeInterface
{
public string Name { get; set; }
public string Phone { get; set; }
}
class ClassB : ISomeInterface
{
public string Name { get; set; }
public string Email { get; set; }
}
...and say this JSON is posted:
{ "Name": "Some Value" }
How would the model binder know which class to use? Would it search all defined classes in all assemblies to find all implementations of the interface? And if so, even if it had smart selection logic based on properties, how would it select between ClassA or ClassB, both of which are compatible?
What you may want to do is either use a type like Dictionary<string, object> that you know will be compatible, dynamic, or go with a concrete class that is a union of everything you need. Alternately, you can create a custom model binder with its own logic for selecting the class you want to instantiate. See this question for more details.

Access to base class from Property Attribute

I'm trying to create attribute which will generate identity number key for each object in class range. So i need to know which class contain parameter connected with attribute.
I create something like this:
class SampleModel
{
[Identity(typeof(SampleModel))]
public int Id { get; set; }
}
public class IdentityAttribute : Attribute
{
private readonly int _step;
private readonly Type _objectType;
public IdentityAttribute(Type type)
{
_step = 1;
_objectType = type;
}
public object GenerateValue()
{
return IdentityGenerator.GetGenerator(_objectType).GetNextNum(_step);
}
}
But i'm wondering is there any method which will allow me to get Type of base class (in this case SampleMethod) in IdentityAttribute constructor without sending it as parameter?
There is no such method -- an instance of Attribute does not know what it was decorating.
But the code that creates the instance does, so depending on usage you could inject this information externally:
var identityAttribute = (IdentityAttribute)Attribute.GetCustomAttribute(...);
// If you can call GetCustomAttribute successfully then you can also easily
// find which class defines the decorated property
var baseClass = ... ;
// And pass this information to GenerateValue
var value = identityAttribute.GenerateValue(baseClass);

Categories

Resources