views:

58

answers:

1

Hi,

I am using asp.net MVC 2 to develop a site. IUser is used to be the interface between model and view for better separation of concern. However, things turn to a little messy here. In the controller that handles user sign on: I have the following:

        IUserBll userBll = new UserBll();
        IUser newUser = new User();

        newUser.Username = answers[0].ToString();
        newUser.Email = answers[1].ToString();

        userBll.AddUser(newUser);

The User class is defined in web project as a concrete class implementing IUser. There is a similar class in DAL implementing the same interface and used to persist data. However, when the userBll.AddUser is called, the newUser of type User can't be casted to the DAL User class even though both Users class implementing the interface (InvalidCastException).

Using conversion operators maybe an option, but it will make the dependency between DAL and web which is against the initial goal of using interface.

Any suggestions?

A: 

You should have a project which handles dependency injection. This project references your Domain project (where IUserBll is defined), and the project which has the DLL implementation. So your MVC project will reference the dependency injection project and given a particular interface, ask the DI for an implementation of it.

Have a look at StructureMap or Castle Windsor.

    //Global.asax
    protected void Application_Start()
    {
        ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
    }

    //Dependency Injection Project:
    public class StructureMapControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(Type controllerType)
        {
            if (controllerType != null)
            {
                return (IController)ObjectFactory.GetInstance(controllerType);
            }
            return null;
    }
}

That way your controller can look more like:

public class SomeController
{
  private IUserBll _repository;
  public SomeController(IUserBll repository)
  {
    _repository = repository;
  }

  [AcceptVerbs(HttpVerbs.Post)]
  public ActionResult Index(Someform f)
  {
      ...
      _repository.AddUser(...);
  }
}

When you use a StructureMap controller factory for example, MVC will get the dependencies into your controller behind the scenes.

CRice
Yes, I understand the benefit of DI. The main issue here, however, is dealing with the User types. _repository.AddUser(...) still pass in a User object, right?
Icerman
My point is you can get around making "the dependency between DAL and web which is against the initial goal of using interface" by making the dependency between (DI Project and Web) and (The project with IUserBll and Web). The web project never references / has the dependency to the DAL project. The controller factory will make the repository instantiation of DAL.UserBll and return it as IUserBll.
CRice
Agreed. Another puzzle I had is IUser and its implementations in both DAL and Web. IUser defines common properties and DAL and Web may have different implentation which additional properties that only DAL or Web care. But it looks to me that instead of casting Web User to DAL user, I need to populate DAL user using IUser properties than assign DAL User specific properites in IUserBll.AddUser(IUser).
Icerman
Well, I don't recommend putting domain types (IUser) in the DAL project. Keep them in their own project and the DAL repositories can still reference, fill and return them.
CRice
Yes, IUser is in a separate project and DAL can reference. The User type below is defined in DAL and the cast throw InvalidCastException: public int AddUser(IUser user) { int ret = 0; using (MyEntities entities = new MyEntities()) { entities.AddToUsers(user as User); // <--exception thrown here---- entities.SaveChanges(); } return ret; } I think this cast need to be replaced by assigning properties define in IUser... Not sure if there are any alternatives?
Icerman
if "user as User" throws InvalidCast, that would suggest that User does not implement the IUser interface.
CRice