3

I have been looking into updating an existing codebase to better follow design patterns, principals, handle unit testing, separating concerns, etc. I am new to implementing a lot of these concepts so I am still doing a lot of research and trying to see how they could be implemented in the current codebase.

Currently each business entity has its own vb file. Within that vb file contains the entity, entity collection, and entity dalc classes for that entity. If you want to perform a database operation on the entity you would do so by calling Enity.Save, Entity.Delete, etc. These methods on the entity class would create the entity dalc object and then call the Save, Delete, etc. method on the entity dalc object. The dalc would then call a Save, Delete, etc. stored procedure through a SqlHelper class that handles the low level stuff.

Each entity class requires a Location object to be passed into it's constructor. This object is used to know what database the user is logged into as well as create the appropriate connection string to the database. The databases all have the same schema; they just have different names and can live on different SQL instances. Basically each client has their own database and the Location object hits up a shared database to find out what SQL instance the client needs to connect to based on the client's name which is stored in a cookie.

I have been looking into a more Model/Repository/Service approach but the Location object is throwing me off, especially since it too needs to access the database to get the information it needs to create the correct connection string. The repository objects need the connection string, but all of the examples I have seen have it hardcoded in the class. I am thinking the repository objects will need to take in an interface of the Location object but I'm not sure if the MVC project would do that directly or pass it into the service objects and they would handle it. At what point does the Location object get created, since it too needs to access the database in order for it to create the connection string, how does it get created?

I am also not clear on how the MVC project would interact with the Service and Repository layers. It seems like everything should run through the service objects, but for testing you would want them to take in an interface for the repository. Doing this would mean the MVC project would need to pass in the repository object, but it doesn't seem like the MVC project should know about the repository objects. However, if you are just doing basic CRUD it seems like it would be simpler to have the MVC project directly call those methods on the repository objects instead of running them through a service object.

Here is an example of what I am currently looking into. The plan is to use ADO.NET and SQL Server for now but possibly switch to an ORM or even a different SQL backend in the future. I am hoping the Model/Repository/Service approach will make it easy to make those changes in the future so if not feel free to offer advice on that as well.

Project.Model

public class Person
{
    public int Id;
    public string Name;
}

Project.Repository

public class PersonRepository
{
    public Person FindById(int id)
    {
        // Connect to the database based on the Location's connection string
    }
}

Project.Service

public class PersonService
{
    private IPersonRepository _personRepository;

    // Should this even take in the repository object?
    public PersonService(IPersonRepository personRepository)
    {
        _personRepository = personRepository;
    }

    // Should the MVC project call this directly on the repository object?
    public Person FindById(int id)
    {
        return _personRepository.FindById(id);
    }
}

Project.MCV

// I think the Location object needs to come from here, as the client name is
// in the cookie. I'm not sure how the controllers should interact with the
// service and repository classes.
5
  • Can you provide a more specific question/concern? Are you looking for ways to interact with the service layer? Commented Jan 26, 2014 at 16:09
  • @rae1 I kind of jumbled several questions into one post. My main question is how to get the correct connection string into the repository but I am also not clear on how the MVC project should interact with the service/repository objects. It seems like the MVC project should inject the repository object into the service object, or just directly call the CRUD methods on the repository object. But I'm not sure if the MC project should even have access to the repository objects. Commented Jan 26, 2014 at 16:15
  • 1
    @Billy I'm not an expert, so I cant give you a full answer. But stil I can give you an advice: "digg-up" some information about NHibernate (ORM) and SessionFactories, and forgot about generic operations on the IRepository interface. Work with IQueryable directly from the Session context. My answer may be abstract now but when you'll read more about NHibernate you get the point Commented Jan 26, 2014 at 16:43
  • @Christian I have came across what you are suggesting but have mostly ignored it as I wasn't using an ORM. I'll dig into further to see what I can learn. Commented Jan 26, 2014 at 16:47
  • @Billy Wish you good luck my friend. You'd love it :) Commented Jan 26, 2014 at 16:56

1 Answer 1

2

I second @Christian's advice. Using an ORM will greatly simplify your interactions with the underlaying data store; and NHibernate is a great choice.

However, in your example, the common way to interact with the data layer from the presentation (aka ASP.NET MVC project) is to inject the service as a dependency for your controller.

There are several ways to do this, the simplest, most straightforward is to use a dependency injection framework (like Unity) to instantiate your services as you specify in the controller's constructor,

public class PersonController : Controller
{
     private readonly IPersonService personService;

     public PersonController(IPersonService personService)
     {
         this.personService = personService;
     }
}

Another way is to implement your own ControllerFactory implementation and inject the required services as needed. It is a lot more work, but if you have the time, you can lear a ton about the over all flow of the ASP.NET MVC routing flow and a bit of DI itself.

In a DI framework you (mostly) register interfaces with concrete classes implementations, basically saying that when an instance of IPersonRepository is required, use a new instance of PersonRepositoryImpl. With these registration rules in place, the DI framework will then recursively instantiate each dependency as it appears in the class constructor.*

In other words, when you request an instance of PersonController, the DI framework will then try to create an instance of type PersonController; when it sees that the constructor required an argument of type IPersonService, it first tries to instantiate one based on the same rules. Thus, the process starts again until all dependencies have been resolved and injected into the constructor for PersonController,

resolve PersonController
  -> construct PersonController(IPersonService personService) 
    -> resolve IPersonService with PersonService
      -> construct PersonService(IPersonRepository personRepository)
        -> resolve IPersonRepository with PersonRepository
          -> construct PersonRepository() <- this one has no dependencies

And back up the stack until a new instance of PersonController is returned.

*For this to work you must have only one public constructor for the given class, where each argument is a dependency that needs to be resolved (your examples nailed this down). If the type of the dependency is not registered with the framework, the resolution will fail. If there are multiple public constructors, the resolution will also fail (there is no sure way to determine which one to use), unless you register which constructor should be used (usually using attributes, but it depends on the DI framework in place). Some DI frameworks (like Unity) might allow you to have no constructor at all (which defaults to an empty, parameterless constructor) and have dependencies as public properties marked with a dependency attribute. I suggest not to use this method as it provides no way of knowing from a consumer class what dependencies the class needs (without using Reflection to inspect all properties and see which ones are marked as dependencies), which will in turn cause a myriad of NullReferenceExceptions.

Sign up to request clarification or add additional context in comments.

1 Comment

How does the PersonService access the repository? For testing purposes it seems like IPersonRepository would need to be injected into the service's constructor as the service is being injected into the controller's constructor. If that is how it should be I'm guessing something like Unity would also handle that?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.