Repository as parameter - c#

I created an Generic dropdown list to use in my controller:
GenericDropDownList("myDropDown");
private void GenericDropDownList(string dropdownName, object selectedDepartment = null) {
var dropdownQuery = unitOfWork.SalesRepository.Get(orderBy: q => q.OrderBy(d => d.FirstName));
ViewData[dropdownName] = new SelectList(dropdownQuery, "LastName", "LastName", selectedDepartment);
}
This seems to work fine. What I'm trying is to make the unitOfWork.TestRepository dynamic, so that I can use every available repository in the function:
GenericDropDownList("myDropDown", SalesRepository);
private void GenericDropDownList(string dropdownName, object repository, object selectedDepartment = null) {
var dropdownQuery = repository.Get(orderBy: q => q.OrderBy(d => d.FirstName));
ViewData[dropdownName] = new SelectList(dropdownQuery, "LastName", "LastName", selectedDepartment);
}
The above doesn't work. I get the following error:
Error CS1061 'object' does not contain a definition for 'Get' and no
extension method 'Get' accepting a first argument of type 'object'
could be found
Is it possible to make the dropdown as dynamic as I want?

The class object does not have a .Get method so it makes sense that this does not compile.
Using dynamic will fix that because then .Get is resolved at runtime, albeit at a performance cost, and with risk of a runtime error if .Get does not exist at runtime.
The best approach in my opinion is to use an interface:
private void GenericDropDownList(string dropdownName, IRepository repository, object selectedDepartment = null)
{
// ...
}
When using Entity Framework you can impose this interface on the Repository classes by using partial classes:
public partial class ThisRepository : IRepository
{
}
public partial class ThatRepository : IRepository
{
}
A catch will be that an interface can not define a property such as FirstName, so you either have to define a method for that, or use a Func<IRepository, string> for the sorting bit.

If you want a dynamic object use the dynamic type.
Or try casting it to an appropriate type:
(repository as type).Get(...)

The correct approach would be to have all your repositories implement a common interface with common methods.
For example, you can create the interface IRepository, or IRepository<TSource> if you want it to be a little more specific.
The problem is that TSource should have a FirstName property according to your expected code.
Are you sure that all repositories will have entities with FirstName property?
If the answer is no, then you cannot create such generic method (You'd need to redefine your logic, or create a specific interface that will have entities with this property, but you won't be able to pass in any repository, only the ones that implement this interface).
If the answer is yes, then you can create a base class for all your source entities (BaseEntity, for instance), which would have the FirstName property.
Supposing the answer was yes, then you can change your method's signature to:
private void GenericDropDownList(string dropdownName, IRepository<TSource> repository, object selectedDepartment = null) where TSource : BaseEntity
You would then be able to call it:
GenericDropDownList("myDropDown", SalesRepository); //SalesRepository should implement IRepository<Sale>, where Sale : BaseEntity

Related

How to inject a generic interface into MVC controller using Ninject

I have the following situation:
an interface:
public interface ITest<T> where T:class
{
void Delete(T item);
}
the abstract implementation:
public abstract class Test<T>:ITest<T> where T:class
{
private readonly ApplicationDbContext _context;
protected Test(ApplicationDbContext context){
_context=context;
}
public void Delete(T item) { }
}
final class:
public class RepoTest:Test<FirstEntity>
{
public void DoSomething() { }
}
I have a MVC Controller, which looks like this:
public abstract class MyController<T>:Controller where T:class
{
private readonly ITest<T> _test;
protected MyController(ITest<T> test)
{
_test = test;
}
}
For each entity, I create a controller, inherited from MyController, and base on Entity I want ninject to inject the specific class.
For this I try to use this bindings:
kernel.Bind(typeof(ITest<>)).To(typeof(Test<>)).InRequestScope();
kernel.Bind(x=>x.FromAssemblyContaining(typeof(Test<>))
.SelectAllClasses()
.InheritedFrom(typeof(Test<>))
.BindToSelf());
Unfortunatly I alwasys got this kind of errors:
Error activating ITest{Tool}
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency ITest{Tool} into parameter test of constructor of type ToolsController
1) Request for ToolsController
Suggestions: 1) Ensure that you have defined a binding for
ITest{Tool}. 2) If the binding was defined in a module, ensure that
the module has been loaded into the kernel. 3) Ensure you have not
accidentally created more than one kernel. 4) If you are using
constructor arguments, ensure that the parameter name matches the
constructors parameter name. 5) If you are using automatic module
loading, ensure the search path and filters are correct.
How can I tell to Ninject, to inject the class base on the Entity type?
The code as it is written currently won't work.
You have two options:
Use generic:
Because your controller is expecting ITest<T> which is bound to an abstract class Test<T> which can't be instantiated.
You have to make a concrete but Generic class Test<T> and add a binding for ApplicationDbContext which will automatically work.
Use Reflection to find the right type at binding, e.g.:
Important!!! remove both of your kernel.Bind() calls.
// this will find classes which, like RepoTest, are derived from Test<>
var allDerivedTypes = typeof(Test<>).Assembly.GetExportedTypes().Where(x => x.BaseType.IsGenericType && x.BaseType.GetGenericTypeDefinition() == typeof(Test<>)).ToList();
// ideally, you'd find some way to constrain all your models.
// what you need for this foreach is all of the entities that can be present in things like RepoTest
foreach(var t in typeof(Tool).Assembly.GetExportedTypes())
{
// For each entity, get a runtime representation of Test<Entity>
var targetType = typeof(Test<>).MakeGenericType(t);
// Check if there is a class derived from Test<Entity>
var potentiallyPresentImplementation = allDerivedTypes.FirstOrDefault(x => targetType == x.BaseType); // here you might want to decide how to handle multiple instances of the same generic base
// Found one, so bind it
if(potentiallyPresentImplementation != null)
{
kernel.Bind(targetType ).To(potentiallyPresentImplementation ).InRequestScope();
}
}
Note: method 2 is currently assuming that all models and Test<> derivatives are in one assmebly, respecitvely. You'd need to add a little more reflection magic to inspect all referenced assemblies if this is not the case.
After this, the controller will get RepoTest injected. Although to be honest with you, approach 1. is better :)

create a generic class for the type name

there is a class
public class Repository <TKey, TEntity>
{
public ICollection<TEntity> Get()
{
using (var session = NHibernateHelper.OpenSession())
{
if (typeof(TEntity).IsAssignableFrom(typeof(IActualizable)))
return session.CreateCriteria(typeof(TEntity)).Add(Restrictions.Lt("ActiveTo", DBService.GetServerTime())).List<TEntity>();
return session.CreateCriteria(typeof(TEntity)).List<TEntity>();
}
}
}
how to create it, knowing only the name of TEntity?
Example:
class Game
{
}
string nameEntity = "Game";
var repository = new Repository< long, ??? >();
There's three parts to this:
getting the Type from the string "Game"
creating the generic instance
doing something useful with it
The first is relatively easy, assuming you know a bit more - for example, that Game is in a particular assembly and namespace. If you know some fixed type in that assembly, you could use:
Type type = typeof(SomeKnownType).Assembly
.GetType("The.Namespace." + nameEntity);
(and check it doesn't return null)
Then we need to create the generic type:
object repo = Activator.CreateInstance(
typeof(Repository<,>).MakeGenericType(new[] {typeof(long), type}));
however, note that this is object. It would be more convenient if there was a non-generic interface or base-class that you could use for Repository<,> - I would put serious though into adding one!
To use that, the easiest approach here will be dynamic:
dynamic dynamicRepo = repo;
IList entities = dynamicRepo.Get();
and use the non-generic IList API. If dynamic isn't an option, you'd have to use reflection.
Alternatively, adding a non-generic API would make this trivial:
interface IRepository {
IList Get();
}
public class Repository <TKey, TEntity> : IRepository {
IList IRepository.Get() {
return Get();
}
// your existing code here
}
then it is just:
var repo = (IRepository)Activator.CreateInstance(
typeof(Repository<,>).MakeGenericType(new[] {typeof(long), type}));
IList entities = repo.Get();
Note: depending on the data, IList might not work - you might need to drop to the non-generic IEnumerable instead.

Generic Method to fill properties?How do you do it in .net 2.0?

I have 2 classes Customer and Person(share exactly the same properties and these properties should be filled in by a request
I would like to write a generic method like
//Usage Customer myCustomer =CreateCustomerOrPerson<Customer>(myRequest)
//Usage Person myPerson =CreateCustomerOrPerson<Person>(myRequest)
public static T FillPropertiesOfCustomerOrPerson<T>(Request request)
{
//not sure how I would I do it to fill the properties.
// T a = default(T);
//a.Name=request.Name;
//a.Surname=request.Surname;
// if (a is Customer)
//{
//?
/// }
return (T)a;
}
How would you write this generic method to avoid having 2 methods (one for customer and one for person)?
Edit
I have no control over these classes. I just need to fill the properties and I was wondering if I could write a generic method rather than 2 specific ones.
Given the requirements, your options are somewhat limited. If you don't want to make use of the dynamic keyword (due to .NET version or whatever), you could do this old-style and use reflection. A possible implementation of that follows:
private const string PROP_NAME = "Name";
private const string PROP_SURNAME = "Surname";
public static T FillPropertiesOfCustomerOrPerson<T>(Request request)
where T : new()
{
if (typeof(T) != typeof(Person) && typeof(T) != typeof(Customer))
{
throw new Exception(
string.Format("{0} is not a supported type.", typeof(T).Name)
);
}
PropertyInfo name = typeof(T).GetProperty(PROP_NAME);
PropertyInfo surname = typeof(T).GetProperty(PROP_SURNAME);
T t = new T();
name.SetValue(t, request.Name, null);
surname.SetValue(t, request.Surname, null);
return t;
}
Optionally, you could remove the where T : new() and replace the instantiation code with something like this:
T t = (T)Activator.CreateInstance(typeof(T));
+1 for CodeInChaos.
You should put the responsibility for reading properties from Request with the classes that have the properties.
The best way would be to have either a base class or an interface that provides you with, let's say, a FillProperties method that takes a Request. Then put a restriction on T for your method that specifies the base class or interface and call T.FillProperties(request).
If you can't fix the design, I'd use duck typing instead. C# 4 has the dynamic keyword. You'll lose type safety, and refactoring support, but at least you don't repeat yourself.
public static void FillPropertiesOfCustomerOrPerson(dynamic person, Request request)
{
person.Name=request.Name;
person.Surname=request.Surname;
}
Have Person and Customer either inherit from a base class (e.g. Customer : Person) or implement a common interface. You can then just have your method accept the base type instead:
public static Person FillPropertiesOfPerson(Request request)
{
Person returnValue = new Person();
returnValue.Name = request.Name;
// etc...
return Person;
}
Note that if Person and Customer are partial classes (for example the proxy classes generated when you consume a web service) then you can use a partial-ness of these classes to do this:
// Define your interface to match the properties which are common to both types
interface IPerson
{
string Name
{
get;
set;
}
}
// Then use partial declarations like this (must be in the same namespace as the generated classes)
public partial class Person : IPerson { }
public partial class Customer : IPerson { }
This will only work if Person and Customer declare exactly the same properties (and are partial classes obviously!), however if there are some slight mismatches then you can use your partial definition to do some "fudging."
Failing that the only method I'm aware of is to use reflection to set the properties, however this isn't typesafe, would incur some performance penalties and is all round not a great idea (I'd probably rather write two identical methods than resort to reflection for something like this).

Creating a Generic Save() Method for Models

I have a fairly simple system, and for the purposes of this question there are essentially three parts: Models, Repositories, Application Code.
At the core are the models. Let's use a simple contrived example:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
In that same project is a generic repository interface. At its simplest:
public interface IRepository<T>
{
T Save(T model);
}
Implementations of that interface are in a separate project and injected with StructureMap. For simplicity:
public class PersonRepository : IRepository<Person>
{
public Person Save(Person model)
{
throw new NotImplementedException("I got to the save method!");
// In the repository methods I would interact with the database, or
// potentially with some other service for data persistence. For
// now I'm just using LINQ to SQL to a single database, but in the
// future there will be more databases, external services, etc. all
// abstracted behind here.
}
}
So, in application code, if I wanted to save a model I would do this:
var rep = IoCFactory.Current.Container.GetInstance<IRepository<Person>>();
myPerson = rep.Save(myPerson);
Simple enough, but it feels like it could be automated a lot. That pattern holds throughout the application code, so what I'm looking to do is create a single generic Save() on all models which would just be a shorthand call to the above application code. That way one would need only call:
myPerson.Save();
But I can't seem to figure out a way to do it. Maybe it's deceptively simple and I'm just not looking at it from the correct angle. At first I tried creating an empty ISaveableModel<T> interface and intended to have each "save-able" model implement it, then for the single generic Save() method I would have an extension on the interface:
public static void Save<T>(this ISaveableModel<T> model)
{
var rep = IoCFactory.Current.Container.GetInstance<IRepository<T>>();
model = rep.Save(model);
}
But it tells me that rep.Save(model) has invalid arguments. It seems that it's not wiring up the type inference as I'd hoped it would. I tried a similar approach with a BaseModel<T> class from which models would inherit:
public class BaseModel<T>
{
public void Save()
{
this = IoCFactory.Current.Container.GetInstance<IRepository<T>>().Save(this);
}
}
But the compiler error is the same. Is there a way to achieve what I'm trying to achieve? I'm very flexible on the design, so if I'm going about something all wrong on an architectural level then I have room to step back and change the big picture.
Would a generic extension method solve it?
public static T Save<T>(this T current)
{
var rep = IoCFactory.Current.Container.GetInstance<IRepository<T>>();
rep.Save(current);
}
You can then constrain it to your ISaveableModel<T> interface. Return type above not implemented, but you can put it to a boolean or status flag, whatever.
In both approaches, the parameter to the Save() function is not of type T. In the first one, it is ISaveableModel<T>, and in the second, it is BaseModel<T>. Since the repository is a generic based on T, Save method will expect a variable of type T. You can add a simple cast to T before you call Save to fix it.
Alternatively, your IRepostory<T> can be changed to
public interface IRepository<T>
{
T Save(ISaveableModel<T> model);
}
which makes more sense.

In a Generic Provider how to find and edit properties of T? (C#)

So, I'm making a generic provider for my repositories implementation which will be used by my BaseController (ASP.NET MVC 2) for low-level objects. These objects have common operations, such as Activate/Deactivate/Delete/Edit, so I'll always be working with the same property on each. The problem is, since I don't know what T is, I obviously don't have access to its properties.
So, my question is, can someone show me how to get the properties I need out of the objects. I've seen some people talking about Reflection, others Expression Trees, neither of which I know how to use.
I do have a generic repository which I believe uses Expression Trees (copied it from some website), but again, I don't know what I'm doing with it... If it helps, here's what I've got so far:
public class Provider<T> where T : class {
private readonly Repository<T> Repository = null;
public Provider(
Repository<T> Repository) {
this.Repository = Repository;
}
public void Activate(
int Id) {
T Entity = this.Repository.Select(Id);
// Need to get the property here, change it and move on...
this.Repository.Submit();
}
}
I'd appreciate any help on this.
If those classes have common operations, sounds like they should inherit from the same base or implement the same interface, correct? If so, use that interface/base as the constraint for T
public class Provider<T> where T : ICommonInterface
You will then have compile-time access to the shared members provided by the interface or base class.
You could make an action
public void Activate(int Id, Action<T> doSomething)
{
T Entity = this._repository.Select(Id);
// Need to get the property here, change it and move on...
doSomething(Entity);
_repository.Submit();
}
Then using the Action delegate (in this example via a lambda) the properties will be known when activate is called:
prov.Activate(5, x => x.Address = "fgfgf");
The best solution will be to give the objects a common base type, and constrain the type parameter T to be of that type. Then you'll have access to the methods or properties of the common base type at compile time:
public class Provider<T> where T : ICommon
{
...
}
or
public class Provider<T> where T : CommonBase
{
...
}
If that's not possible, then without a common base type the best you can do is reflect upon the objects to look for and invoke the property that you are interested in:
public void Activate(int Id)
{
T entity = this.Repository.Select(Id);
// Interrogate the type of the entity and get the property called "MyPropertyName"
PropertyInfo pi = entity.GetType().GetProperty("MyPropertyName");
// Invoke the property against the entity instance - this retrieves the
// value of the property.
var value = (YourType)(pi.GetValue(entity, null));
// Do somethign with the value...
this.Repository.Submit();
}
I should add that reflection is comparatively expensive and you also lose the compile time verification. But it's handy in cases like these.
You can get a MethodInfo object for working with methods by calling:
MethodInfo mi = entity.GetType().GetMethod("MyMethodName");

Categories

Resources