Implementing a modern web application with Web API on top of old services
- by Gaui
My company has many WCF services which may or may not be replaced in the near future. The old web application is written in WebForms and communicates straight with these services via SOAP and returns DataTables.
Now I am designing a new modern web application in a modern style, an AngularJS client which communicates with an ASP.NET Web API via JSON. The Web API then communicates with the WCF services via SOAP.
In the future I want to let the Web API handle all requests and go straight to the database, but because the business logic implemented in the WCF services is complicated it's going to take some time to rewrite and replace it.
Now to the problem: I'm trying to make it easy in the near future to replace the WCF services with some other data storage, e.g. another endpoint, database or whatever. I also want to make it easy to unit test the business logic.
That's why I have structured the Web API with a repository layer and a service layer. The repository layer has a straight communication with the data storage (WCF service, database, or whatever) and the service layer then uses the repository (Dependency Injection) to get the data. It doesn't care where it gets the data from. Later on I can be in control and structure the data returned from the data storage (DataTable to POCO) and be able to test the logic in the service layer with some mock repository (using Dependency Injection).
Below is some code to explain where I'm going with this. But my question is, does this all make sense? Am I making this overly complicated and could this be simplified in any way possible? Does this simplicity make this too complicated to maintain? My main goal is to make it as easy as possible to switch to another data storage later on, e.g. an ORM and be able to test the logic in the service layer. And because the majority of the business logic is implemented in these WCF services (and they return DataTables), I want to be in control of the data and the structure returned to the client.
Any advice is greatly appreciated.
Update 20/08/14
I created a repository factory, so services would all share repositories. Now it's easy to mock a repository, add it to the factory and create a provider using that factory.
Any advice is much appreciated. I want to know if I'm making things more complicated than they should be.
So it looks like this:
1. Repository Factory
public class RepositoryFactory
{
private Dictionary<Type, IServiceRepository> repositories;
public RepositoryFactory()
{
this.repositories = new Dictionary<Type, IServiceRepository>();
}
public void AddRepository<T>(IServiceRepository repo) where T : class
{
if (this.repositories.ContainsKey(typeof(T)))
{
this.repositories.Remove(typeof(T));
}
this.repositories.Add(typeof(T), repo);
}
public dynamic GetRepository<T>()
{
if (this.repositories.ContainsKey(typeof(T)))
{
return this.repositories[typeof(T)];
}
throw new RepositoryNotFoundException("No repository found for " + typeof(T).Name);
}
}
I'm not very fond of dynamic but I don't know how to retrieve that repository otherwise.
2. Repository and service
// Service repository interface
// All repository interfaces extend this
public interface IServiceRepository
{
}
// Invoice repository interface
// Makes it easy to mock the repository later on
public interface IInvoiceServiceRepository : IServiceRepository
{
List<Invoice> GetInvoices();
}
// Invoice repository
// Connects to some data storage to retrieve invoices
public class InvoiceServiceRepository : IInvoiceServiceRepository
{
public List<Invoice> GetInvoices()
{
// Get the invoices from somewhere
// This could be a WCF, a database, or whatever
using(InvoiceServiceClient proxy = new InvoiceServiceClient())
{
return proxy.GetInvoices();
}
}
}
// Invoice service
// Service that handles talking to a real or a mock repository
public class InvoiceService
{
// Repository factory
RepositoryFactory repoFactory;
// Default constructor
// Default connects to the real repository
public InvoiceService(RepositoryFactory repo)
{
repoFactory = repo;
}
// Service function that gets all invoices from some repository (mock or real)
public List<Invoice> GetInvoices()
{
// Query the repository
return repoFactory.GetRepository<IInvoiceServiceRepository>().GetInvoices();
}
}