I am developing an mvc app with the following N tier structure:
DataAccess
Repository
Models
BusinessLogic
In my BusinessLogic folder I have an interface IClinicBusiness and a class ClinicBusiness that interfaces with IClinicBusiness.
The ClinicBusiness class is as follows:
public void AddClinic(Clinic c)
{
var cr = new ClinicRepository();
var clinc = new Clinic();
if (c != null)
{
clinc.ClinicName = c.ClinicName;
clinc.ClinicLocation = c.ClinicLocation;
}
cr.InsertClinic(c);
cr.Save();
}
}
The ClinicBusiness class implements a method from the Repository class library eg. InsertClinic();
public ClinicRepository()
{ }
public ClinicRepository(DataContext clinics)
{
this.clinic = clinics;
}
public IEnumerable<Clinic> GetClinics()
{
return clinic.Clinics.ToList();
}
public Clinic GetClinicByID(int ClinicId)
{
return clinic.Clinics.Find(ClinicId);
}
public void InsertClinic(Clinic c)
{
clinic.Clinics.Add(c);
}
In my controller I have an action
public ActionResult CreateClinic(Clinic c)
{
var clinicBusiness = new ClinicRepository();
return View(clinicBusiness.InsertClinic(c));
}
I get the following error cannot convert from 'void' to 'object'
Can someone please guide me?
Depending on your requirements, I think you want to change your repository InsertClinic method to
public Clinic InsertClinic(Clinic c)
{
clinic.Clinics.Add(c);
return c;
}
Or change your Action to
public ActionResult CreateClinic(Clinic c)
{
var clinicBusiness = new ClinicRepository();
clinicBusiness.InsertClinic(c)
return View(c);
}
Again, it just depends on what your trying to accomplish and your view model.
Related
I am having a difficult time figuring out how to create a 1:1 mapping between objects in a container using AutoFac. I am getting resolution errors and the documentation is too terse with not enough examples.
Here's the rule I would like to use to resolve my dependencies:
An IHouse object can only be constructed using an IDoor parameter of a specific concrete type, creating a 1:1 mapping between IHouse and IDoor types.
As am example, using the code below, if I resolve the container using a MonkeyDoor, it should give me back a fully constructed MonkeyHouse and only a MonkeyHouse object.
[TestClass]
public class HousingDeveloperTest
{
[TestMethod]
public void TestMethod1()
{
// Load them from an assembly or disc. We are interested in IHouse and IDoor types
var builder = new ContainerBuilder();
// Get all the houses
var assembly = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith(nameof(House))).AsImplementedInterfaces();
// get all the doors
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith(nameof(Door))).AsImplementedInterfaces();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var house = container.Resolve<IDoor>(new TypedParameter(typeof(MonkeyDoor), new MonkeyDoor()));
}
}
}
public interface IDoor
{
void Open();
}
public abstract class Door : IDoor
{
public void Open()
{
Trace.WriteLine($"Opening {GetType().ToString()}.");
}
}
// Only works with Victorian homes
public class VictorianDoor : Door
{
}
// Only works with Craftsman homes
public class CraftsmanDoor : Door
{
}
// Only works with monkey homes
public class MonkeyDoor : Door
{
}
public interface IHouse
{
void OpenHouse();
}
public abstract class House : IHouse
{
public IDoor Door;
protected House(IDoor door)
{
Door = door;
Trace.WriteLine($"Building this {this.GetType()} with {door.GetType()} door.");
}
public void OpenHouse()
{
Trace.WriteLine($"We're having an open house on this wonderful {this.GetType().ToString()}.");
Door.Open();
}
}
// Doors must match the homes. (i.e. No monkey doors on a Victorian or Craftsman home.)
public class VictorianHouse : House
{
public VictorianHouse(VictorianDoor door) : base(door)
{
}
}
public class CraftsmanHouse : House
{
public CraftsmanHouse(CraftsmanDoor door) : base(door)
{
}
}
public class MonkeyHouse : House
{
public MonkeyHouse(MonkeyDoor door) : base(door)
{
}
}
My DbContext implementation implements two interfaces.
I'm trying to follow best practices and instantiate one DbContext instance per HTTP request.
However, I have a controller action where I need to instantiate two classes, each of which takes different interface in constructor.
I am worried if in that scenario, for that specific action, two DbContext instances would be raised.
I've setup my ContainerBuilder like this:
builder.RegisterType<MyDbContext>()
.As<IWorkflowPersistenceStore>()
.As<IDocumentPersistenceStore>()
.InstancePerHttpRequest();
builder.RegisterType<WorkflowManager>().As<IWorkflowManager>().InstancePerHttpRequest();
builder.RegisterType<DocumentManager>().As<IDocumentManager>().InstancePerHttpRequest();
public class OperationController : Controller
{
private IWorkflowManager _workflowManager;
private IDocumentManager _documentManager;
public OperationController(IWorkflowManager workflowManager, IDocumentManager documentManager)
{
_workflowManager = workflowManager;
_documentManager = documentManager;
}
public ActionResult SaveWorkflowDocument(...)
{
// will my managers point to same DbContext?
_workflowManager.DoSomething(...);
_documentManager.DoSomethingElse(...);
return View();
}
}
public class WorkflowManager : IWorkflowManager
{
private IWorkflowPersistenceStore _store;
public WorkflowManager(IWorkflowPersistenceStore store)
{
_store = store;
}
}
public class DocumentManager : IDocumentManager
{
private IDocumentPersistenceStore _store;
public DocumentManager (IDocumentPersistenceStore store)
{
_store = store;
}
}
Is this good enough?
Do I have to add .SingleInstance()? I'm worried that it might create singleton for whole application.
I think you're ok with what you have. Test passes:
using Autofac;
using NUnit.Framework;
namespace AutofacTest
{
[TestFixture]
public class ScopeTest
{
[Test]
public void Test()
{
var builder = new ContainerBuilder();
builder.RegisterType<Component>()
.As<IServiceA>()
.As<IServiceB>()
.InstancePerLifetimeScope();
using (var container = builder.Build())
using (var scope = container.BeginLifetimeScope())
{
var a = scope.Resolve<IServiceA>();
var b = scope.Resolve<IServiceB>();
Assert.AreEqual(a, b);
}
}
}
public interface IServiceA { }
public interface IServiceB { }
public class Component : IServiceA, IServiceB { }
}
I have an MVC intranet application which uses EF 6. I have setup the DataAccess project in a separate class library which has EF 6 referenced. I have an entity which implements an interface:
public interface IAuditable
{
DateTime CreatedDateTime { get; set; }
string CreatedBy { get; set; }
}
public class Collection : IAuditable
{
// Properties
}
However, in the SaveChanges method I obviously don't have access to HttpContext.Current.User.Identity.Name as it is in a separate class library, so I was wondering how one would set this in SaveChanges?
public override int SaveChanges()
{
var addedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added);
foreach (var dbEntityEntry in addedEntries)
{
var entity = dbEntityEntry.Entity as IAuditable;
if (entity != null)
{
entity.CreatedDateTime = DateTime.Now;
// how do I set entity.CreatedBy = HttpContext.Current.User.Identity.Name?
}
}
return base.SaveChanges();
}
Edit
Following on from #CodeCaster solution, I have the following:
[BreezeController]
public class BreezeController : ApiController
{
private readonly BTNIntranetRepository _repository;
public BreezeController(BTNIntranetRepository repository)
{
_repository = repository;
_repository.LoggedInUser = HttpContext.Current.User.Identity.Name;
}
// Methods
}
But HttpContext.Current.User is null
This can be solved in many ways.
You're not really showing relevant code, but you can for example give the library class you expose a public string LoggedInUser (or ActingUser or give it a name) property which you set when instantiating it:
public class SomeController : Controller
{
private IDataSource _dataSource;
public SomeController(IDataSource dataSource)
{
_dataSource = dataSource;
_dataSource.LoggedInUser = HttpContext.Current.User.Identity.Name
}
}
You can then simply use that property in your IDataSource.SaveChanges() method:
public override int SaveChanges()
{
// ...
entity.CreatedBy = this.LoggedInUser;
}
I've this interface:
public interface IRepository<T>
{
List<T> List();
T Get(int Id);
bool Add(T entity);
bool Update(T entity);
}
And I've this class:
public class Customer<T> : IRepository<Entities.Customer>
{
public Entities.Customer Get(int Id)
{
var c = new Entities.Customer();
return c;
}
//continue...
}
How can I cast a generic class to a generic interface like so:
//Other method
public IRepositorio<T> DoStuff<T>(int Id)
{
var a = (IRepository<Entities.Customer>)Activator.CreateInstance(typeof(T)); // ok
var b = (IRepository<T>)Activator.CreateInstance(typeof(T)); // Exception: unable to cast
return object; // an object
}
And I call from this MCV controller:
public ActionResult Home()
{
var repo = new Repository();
repo.DoStuff<Customer<Entities.Custormer>>(10);
return View();
}
My conception is ok? This is possible without dynamic?
Based on the code supplied, I've tried the following which compiles OK
public class Entities {
public class Customer {
}
}
public interface IRepository<T> {
T Get(int Id);
}
public class Customer<T> : IRepository<Entities.Customer> {
public Entities.Customer Get(int Id) {
var cliente = new Entities.Customer();
return cliente;
}
}
public class foo {
public static IRepository<T> DoStuff<T>(int Id) {
var a = (IRepository<Entities.Customer>)Activator.CreateInstance(typeof(T));
var b = (IRepository<T>)Activator.CreateInstance(typeof(T));
return b; // an object
}
}
However, I'm not sure what T is meant to be. When I run and call
foo.DoStuff<Entities.Customer>(0);
then I get a runtime error on the var a line, because the class Entities.Customer does not implement the interface IRepository<T>. If I call
foo.DoStuff<Customer<Entities.Customer>>(0);
then I get the runtime error on the 'var b' line, because the class Customer<Entities.Customer> implements IRepository<Entities.Customer> and not IRepository<Customer<Entities.Customer>>
Both exceptions are correct, so hopefully the author of the question can work out where the problem lies from this answer.
Activator.CreateInstance(typeof(T)); - this creates for you new instance of T, which is Entities.Customer in your example, but it looks like you want to create instance of Customer<Entities.Customer>.
I have successfully setup a simple mvc application that lists teams. I'm using Ninject to inject the appropriate repository depending on the controller (thanks to stack overflow ;). All looks good, except that the repository code looks exactly the same. And I know that's wrong. So my TeamRepository has two classes (for now).
public class SwimTeamRepository : ITeamRepository<SwimTeam>
{
private readonly Table<SwimTeam> _teamTable;
public SwimTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SwimTeam>());
}
public IQueryable<SwimTeam> Team
{
get { return _teamTable; }
}
}
public class SoccerTeamRepository : ITeamRepository<SoccerTeam>
{
private readonly Table<SoccerTeam> _teamTable;
public SoccerTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SoccerTeam>());
}
public IQueryable<SoccerTeam> Team
{
get { return _teamTable; }
}
}
They look exactly the same except for the Class and Table name, so clearly I need to re-factor this. What would be the best approach here? Singleton? Factory Method?
Thanks in advance!
You could use generics:
public interface ITeamRepository<T>
{
}
public class TeamRepository<TTeam> : ITeamRepository<TTeam>
where TTeam : Team
{
private readonly Table<TTeam> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<TTeam>());
}
public IQueryable<TTeam> Team
{
get { return _teamTable; }
}
}
public class Team
{
}
public class SwimTeam : Team
{
}
Then use it like so...
public void MyMethod()
{
var repository = new TeamRepository<SwimTeam>();
}
...and set up your IoC container w/ Ninject like so...
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<ITeamRepository<SwimTeam>>
.To<TeamRepository<SwimTeam>>();
}
}
public void MyMethod()
{
var repository = kernel.Get<ITeamRepository<SwimTeam>>();
}
If you want to get REAL generic and have a single repository for ALL of your mapped classes, you can do something like this:
public interface IRepository
{
IQueryable<T> Get<T>() where T : class, new();
}
public class Repository : IRepository, IDisposable
{
private DataContext _dataContext;
public Repository(string connectionString)
{
_dataContext = new DataContext(connectionString);
}
public IQueryable<T> Get<T>()
where T : class, new()
{
return _dataContext.GetTable<T>().AsQueryable();
}
public void Dispose()
{
if (_dataContext != null)
{
_dataContext.Dispose();
_dataContext = null;
}
}
}
...which you could call like so (after setting up your Ninject container)...
using (var repository = kernel.Get<IRepository>())
{
var swimTeam = repository.Get<SwimTeam>();
}
Since Ninject takes care of the life-cycle management of your objects, you don't HAVE to wrap the repository in a using statement. In fact, you don't want to use a using statement there at all if you plan to use the repository more than once within the scope of its lifetime. Ninject will automatically dispose of it when it's life-cycle ends.
Here's a good article by Rob Conery on using this kind of technique to reduce the friction of using different ORMs.
EDIT by keeg:
I Think
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : Team {}
Should be
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : class {}
Please correct if I'm wrong.
Is this what you want?
public class TeamRepository : ITeamRepository<T>
{
private readonly Table<T> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<T>());
}
public IQueryable<T> Team
{
get { return _teamTable; }
}
}