MVC, problem with Mapper passing ViewModel to CreateView - asp.net-mvc

I need some help. I'm using ASP.NET MVC which I am beginner in.
I'm writing an application with a database and 3 tables (2 tables are just for parent child drop downs, and third is for saving data from dropdowns and fill other forms).
I am using Entity Framework with SQL to connect my database to ASP.NET MVC with autogenerated models from database.
I manually make ViewModel of all three tables and their fields and I need to pass all data to 1 view (Create View)
Here is my code from Home controller where I am getting error.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CountryStateContactsViewModel csvm)
{
if (!ModelState.IsValid)
{
return View(csvm);
}
// Error happens here
Contact contactModel = Mapper.Map<CountryStateContactsViewModel, Contact>(csvm);
db.Contacts.Add(contactModel);
db.SaveChanges();
return RedirectToAction("Index");
}
This is the error I get:
An object reference is required for the non-static field, method, or property 'Mapper.Map<CountryStateContactsViewModel, Contact>(CountryStateContactsViewModel)

In order to use AutoMapper , first you should CreateMap between your classes.
public class ContactProfile {
public AutoMapperProfile() {
CreateMap<CountryStateContactsViewModel,Contact>();
}
}
public class AutoMapperConfiguration {
public static void Initialize() {
Mapper.Initialize(cfg = > {
cfg.AddProfile(new ContactProfile());
});
}
}
And finally in your Global.asax:
AutoMapperConfiguration.Initialize()

According to OP comments there is no AutoMapper configuration, and without it AutoMapper cannot resolve mappings.
Define an interface to abstract the mapping methods:
public interface IMappingService
{
TDest Map<TSrc, TDest>(TSrc source) where TDest : class;
TDest Map<TSrc, TDest>(TSrc source, TDest dest) where TDest : class;
}
Implement the interface:
public class MappingService : IMappingService
{
private MapperConfiguration mapperConfiguration;
private IMapper mapper;
public MappingService()
{
mapperConfiguration = new MapperConfiguration(cfg =>
{
// Define here your mapping profiles...
cfg.AddProfile<ViewModelToDomainMappingProfile>();
cfg.AddProfile<DomainToViewModelMappingProfile>();
});
// You may not want to assert that your config is valid, and that's ok.
mapperConfiguration.AssertConfigurationIsValid();
mapper = mapperConfiguration.CreateMapper();
}
public TDest Map<TSrc, TDest>(TSrc source) where TDest : class
{
return mapper.Map<TSrc, TDest>(source);
}
public TDest Map<TSrc, TDest>(TSrc source, TDest dest) where TDest : class
{
return mapper.Map(source, dest);
}
}
Now you have to define your profiles (example):
public class ViewModelToDomainProfile: Profile
{
public ViewModelToDomainProfile()
{
CreateMap<CountryStateContactsViewModel, Contact>();
}
}
public class DomainToViewModelProfile: Profile
{
public DomainToViewModelProfile()
{
CreateMap<CountryStateContactsViewModel, Contact>();
}
}
Finally, inject your IMappingService in your controller:
private readonly IMappingService _mappingService;
public HomeController(IMappingService mappingService) {
_mappingService = mappingService;
}
And use it like so:
_mappingService.Map<CountryStateContactsViewModel, Contact>(viewModel);
I like this solution because it encapsulates everything nicely.
EDIT: #Arsalan Valoojerdi was faster than me. But, this way you have two different approaches.
Note: Do not forget to define your dependency to IMappingService on your IoC container (eg. Ninject).

Related

ASP MVC EF6 Architecture

We have ASP MVC web project. After reading a lot of articles and discussions here in stackoverflow about the correct architechture we have decided to go with the following one, although there is not only one correct way of doing things this is the way we have decided, but we still have some doubts.
We are publishing this here not only to be helped but also to show what we have done in case it is helpful to somebody.
We are working in ASP .NET MVC project, EF6 Code first with MS SQL Server.
We have divided the project into 3 main layers that we have separate into 3 projects: model, service and web.
The model creates the entities and setup the DataContext for the database.
The service make the queries to the data base and transform those entities into DTOs to pass them to the web layer, so the web layer doesn't know anything about the database.
The web uses AutoFac for the DI (dependency Injection) to call the services we have in the service layer and obtain the DTOs to transform those DTOs into Model Views to use them in the Views.
After reading a lot of articles we decided not to implement a repository pattern and unit of work because, in summary, we have read the EF acts as a unit of work itself. So we are simplifying things a little here.
https://cockneycoder.wordpress.com/2013/04/07/why-entity-framework-renders-the-repository-pattern-obsolete/
This is the summary of our project. Now I'm going to go through every project to show the code. We are going to show only a couple of entities, but our project has more than 100 different entities.
MODEL
Data Context
public interface IMyContext
{
IDbSet<Language> Links { get; set; }
IDbSet<Resources> News { get; set; }
...
DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class;
}
public class MyDataContext : DbContext, IMyContext
{
public MyDataContext() : base("connectionStringName")
{
}
public IDbSet<Language> Links { get; set; }
public IDbSet<Resources> News { get; set; }
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
}
}
Here is how we declare the entities
public class Link
{
public int Id{ get; set; }
public string Title { get; set; }
public string Url { get; set; }
public bool Active { get; set; }
}
SERVICES
These are the generic classes we use for all the services.
As you see we use the DTOs to get data from the web layer. Also we connect to the database using Dbset = Context.Set()
public interface IService
{
}
public interface IEntityService<TDto> : IService where TDto : class
{
IEnumerable<TDto> GetAll();
void Create(TDto entity);
void Update(TDto entity);
void Delete(TDto entity);
void Add(TDto entity);
void Entry(TDto existingEntity, object updatedEntity);
void Save();
}
public abstract class EntityService<T, TDto> : IEntityService<TDto> where T : class where TDto : class
{
protected IClientContext Context;
protected IDbSet<T> Dbset;
protected EntityService(IClientContext context) { Context = context; Dbset = Context.Set<T>(); }
public virtual IEnumerable<TDto> GetAll()
{
return Mapper.Map<IEnumerable<TDto>>(Dbset.AsEnumerable());
}
public virtual void Create(TDto entity)
{
if (entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
Dbset.Add(Mapper.Map<T>(entity));
Context.SaveChanges();
}
public virtual void Update(TDto entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));
Context.Entry(entity).State = EntityState.Modified;
Context.SaveChanges();
}
public virtual void Delete(TDto entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));
Dbset.Remove(Mapper.Map<T>(entity));
Context.SaveChanges();
}
public virtual void Add(TDto entity)
{
Dbset.Add(Mapper.Map<T>(entity));
}
public virtual void Entry(TDto existingEntity, object updatedEntity)
{
Context.Entry(existingEntity).CurrentValues.SetValues(updatedEntity);
}
public virtual void Save()
{
Context.SaveChanges();
}
}
We declare the DTOs in this project (this is a very simple example so we don't have to put all the code here):
public class LinkDto
{
public int Id { get; set; }
public string Title { get; set; }
public string Url { get; set; }
public bool Active { get; set; }
}
Then one of our services:
public interface ILinkService : IEntityService<LinkDto>
{
IPagedList<LinkDto> GetAllLinks(string searchTitle = "", bool searchActive = false, int pageNumber = 1, int pageSize = 10);
LinkDto FindById(int id);
LinkDto Test();
}
public class LinkService : EntityService<Link, LinkDto>, ILinkService
{
public LinkService(IClientContext context) : base(context) { Dbset = context.Set<Link>(); }
public virtual IPagedList<LinkDto> GetAllLinks(bool searchActive = false, int pageNumber = 1, int pageSize = 10)
{
var links = Dbset.Where(p => p.Active).ToPagedList(pageNumber, pageSize);
return links.ToMappedPagedList<Link, LinkDto>();
}
public virtual LinkDto FindById(int id)
{
var link = Dbset.FirstOrDefault(p => p.Id == id);
return Mapper.Map<LinkDto>(link);
}
public LinkDto Test()
{
var list = (from l in Context.Links
from o in Context.Other.Where(p => p.LinkId == l.Id)
select new OtherDto
{ l.Id, l.Title, l.Url, o.Other1... }).ToList();
return list;
}
}
As you see we use AutoMapper (version 5 which has changed a little) to transform from Entities to DTOs the data.
One of the doubts we have is if the use of "Dbset.Find" or "Dbset.FirstOrDefault" is correct and also if the use of "Context.Links" (for any entity).
WEB
FInally the web project where we receive the DTOs and transform those DTOs into ModelViews to show in our views.
We need to call, in the Global.asax Application_Start, AutoFac to do the DI so we can use our services.
protected void Application_Start()
{
...
Dependencies.RegisterDependencies();
AutoMapperBootstrapper.Configuration();
...
}
public class Dependencies
{
public static void RegisterDependencies()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
builder.RegisterModule(new ServiceModule());
builder.RegisterModule(new EfModule());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
public class ServiceModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(Assembly.Load("MyProject.Service")).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
}
}
public class EfModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType(typeof(MyDataContext)).As(typeof(IMyContext)).InstancePerLifetimeScope();
}
}
As you see we also call AutoMapper to configure the different maps.
Then in our controllers we have this.
public class LinksController : Controller
{
private readonly ILinkService _linkService;
public LinksController(ILinkService linkService)
{
_linkService = linkService;
}
public ActionResult Index()
{
var links = _linkService.GetAllLinks();
return View(links.ToMappedPagedList<LinkDto, LinksListModelAdmin>());
}
...
public ActionResult Create(LinksEditModelAdmin insertedModel)
{
try
{
if (!ModelState.IsValid) return View("Create", insertedModel);
var insertedEntity = Mapper.Map<LinkDto>(insertedModel);
_linkService.Create(insertedEntity);
return RedirectToAction("Index");
}
catch (Exception ex)
{
throw ex;
}
}
}
Well, this is it...I hope this can be useful for somebody...and also I hope we can have a little help with the questions we have.
1) Although we are separating database from the web project we do need a reference in the web project to initialize the database and also to inject dependencies, is this correct?
2) Is it correct the approach we have done having our Entities->DTOs->ViewModels? It's a little more work but we have everything separated.
3) In the Service project, when we need to reference a different entity than the main one we are using in the service, is it correct to call Context.Entity?
For example, if we need to retrieve also data from the News entity in the links service, is it correct to call "Context.News.Where..."?
4) We do have a little problem with Automapper and EF proxy, because when we call "Dbset" to retrieve data, it gets a "Dynamic proxies" object so Automapper can't find the proper map so, in order to work, we have to set ProxyCreationEnabled = false in the DataContext definition. This way we can get an Entity in order to map it to the DTO. This disables LazyLoading, which we don't mind, but is this a correct approach or there is a better way to solve this?
Thanks in advance for your comments.
For Question no. 2
Entities->DTOs->ViewModels? is good approach
because you are doing the clean separation, the programmer can work together with ease.
The person who design ViewModels, Views and Controllers don't have to worry about the service layer or the DTO implementation because he will make the mapping when the others developpers finish their implementation.
For Question no. 4
When the flag ProxyCreationEnabled is set to false, the proxy instance will not be created with creating a new instance of an entity. This might not be a problem but we can create a proxy instance using the Create method of DbSet.
using (var Context = new MydbEntities())
{
var student = Context.StudentMasters.Create();
}
The Create method has an overloaded version that accepts a generic type. This can be used to create an instance of a derived type.
using (var Context = new MydbEntities())
{
var student = Context.StudentMasters.Create<Student>();
}
The Create method just creates the instance of the entity type if the proxy type for the entity would have no value (it is nothing to do with a proxy). The Create method does not add or attach the entity with the context object.
Also i read some where if you set ProxyCreationEnabled = false the child element will not loaded for some parent object unless Include method is called on parent object.

Using the Repository Pattern and DI to switch between SQL and XML ASP.Net MVC

i have XMLProductRepository and SQLProductRepository. now how could i switch between them dynamically. i am new in DI. so searching google for the same and found a link which discuss a bit. but still do not understand on what basis the repository will be changed and how. here is the code
public interface IProductRepository
{
IEnumerable<Product> GetAll();
Product Get(int id);
Product Add(Product item);
void Remove(int id);
bool Update(Product item);
}
public class XMLProductRepository : IProductRepository
{
public XMLProductRepository() {}
public IEnumerable<Product> GetAll() {}
public Product Get(int id) {}
public Product Add(Product item) {}
public void Remove(int id) {}
public bool Update(Product item) {}
}
public class SQLProductRepository : IProductRepository
{
public SQLProductRepository() {}
public IEnumerable<Product> GetAll() {}
public Product Get(int id) {}
public Product Add(Product item) {}
public void Remove(int id) {}
public bool Update(Product item) {}
}
Unity.Mvc3 is using as Di
public static class Bootstrapper
{
public static void Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
//Register the repository
container.RegisterType<IProductRepository, SQLProductRepository>();
return container;
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
Bootstrapper.Initialise();
}
public class HomeController : Controller
{
private readonly IProductRepository productRepository;
public HomeController(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
i understand the code that dynamically SQLProductRepository instance is getting injecting into controller. so my question is how to inject XMLProductRepository ?
i want to design something in such a way based on url dependency will be injected.
how to achieve it. looking for guide line. thanks
One possible solution is to inject an IProductRepositoryFactory instead of IProductRepository itself. It would look like this:
interface IProductRepositoryFactory
{
IProductRepository GetRepository(string url);
}
Then your HomeController would look like this:
public class HomeController : Controller
{
private readonly IProductRepositoryFactory productRepositoryFactory;
public HomeController(IProductRepositoryFactory productRepositoryFactory)
{
this.productRepositoryFactory = productRepositoryFactory;
}
}
This way, you'll be able to get required implementation of IProductRepository in your controller action at runtime — all you need is to implement the required logic in the IProductRepositoryFactory.GetRepository(url) method.
Here's a controller action example (note that getting current request URL in such a way makes this method less testable):
public Product Get(string id)
{
return productRepositoryFactory
.GetRepository(Request.Url.ToString())
.GetById(id);
}
UPD: The following is an example implementation of IProductRepositoryFactory. Just implement your own decision-making logic that returns an appropriate instance of IProductRepository based on the URL:
public class ProductRepositoryFactory : IProductRepositoryFactory
{
public IProductRepository GetRepository(string url)
{
if (url.Contains("xml")) { return new XMLProductRepository(); }
if (url.Contains("sql")) { return new SQLProductRepository(); }
throw new ArgumentException("url");
}
}
I don't know where you got the code from, perhaps this question, but the two implementations of IProductRepository that you show have two purposes.
SQLProductRepository will read and write data from and to the database.
XMLProductRepository can read XML and maybe write files.
When running code in a unit test, you generally don't want to connect to a database, but you do sometimes want to use data in a unit test. That's where the XML repository comes in handy. You prepare a data set in XML files that you can commit to version control, you inject another implementation of the requested interface - namely one that reads the XML file - and you don't need a database anymore.
That's why you configure your DI container to inject the SQLProductRepository, while in unit tests you or the DI container will provide an XMLProductRepository when the application requests an IProductRepository.
Now if you say that your controller, your business logic, is to choose SQLProductRepository for one particular request, based on the URI, and XMLProductRepository for the other, then using IProductRepository for that purpose is wrong. That is a problem that should not be solved using your DI container.
Introduce two new interfaces instead and apply those to the repositories:
public interface ISqlProductRepository : IProductRepository
{
}
public interface IXmlProductRepository : IProductRepository
{
}
SQLProductRepository : ISqlProductRepository
XMLProductRepository : IXmlProductRepository
And register and inject those:
// Application startup
container.RegisterType<ISqlProductRepository, SQLProductRepository>();
container.RegisterType<IXmlProductRepository, XMLProductRepository>();
// Controller
private readonly ISqlProductRepository _sqlProductRepository;
private readonly IXmlProductRepository _xmlProductRepository;
public HomeController(ISqlProductRepository sqlProductRepository, IXmlProductRepository xmlProductRepository)
{
_sqlProductRepository = sqlProductRepository;
_xmlProductRepository = xmlProductRepository;
}
public ActionResult SqlMethod1()
{
// use _sqlProductRepository
}
public ActionResult XmlMethod2()
{
// use _xmlProductRepository
}
Of course now you can't inject XMLProductRepository for SQLProductRepository anymore, but that's a problem easily solved using mocking.
Anyway based on your current streak of questions, you're trying to learn something about unit testing and dependency injection. Please pick up a decent book and stop tying pieces together from blog posts, which hardly ever explain everything you need to know.

MVC Repository with Unit Of Work, Automapper and Generic Repository

I've been looking at a few blog posts to try and create an appropriate solution for the following requirements but I can't seem to piece them together. Hope fully someone can help.
I've been using Repository pattern with interfaces using Automapper...here's a trimmed down example:
public class BookingRepository : IBookingRepository
{
Entities context = new Entities();
public IEnumerable<BookingDto> GetBookings
{
get { return Mapper.Map<IQueryable<Booking>, IEnumerable<BookingDto>>(context.Bookings); }
}
public BookingDto GetBookingWithProduct(Guid bookingId)
{
return Mapper.Map<BookingDto>(context.Bookings.Include(c => c.Products).SingleOrDefault(c => c.BookingId == bookingId));
}
public void Update(BookingDto bookingDto)
{
var booking = Mapper.Map<Booking>(bookingDto);
context.Entry(booking).State = EntityState.Modified;
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public interface IBookingRepository : IDisposable
{
IEnumerable<BookingDto> GetBookings { get; }
BookingDto GetBooking(Guid bookingId);
void Update(BookingDto bookingDto);
void Save();
}
With a seperate Repository for a different Entity, for example
public class ProductRepository : IProductRepository
{
Entities context = new Entities();
public IEnumerable<ProductDto> GetProducts
{
get { return Mapper.Map<IQueryable<Product>, IEnumerable<ProductDto>>(context.Products); }
}
public ProductDto GetProductWithDesign(int productId)
{
return Mapper.Map<ProductDto>(context.Products.Include(c => c.Designs).SingleOrDefault(c => c.ProductId == productId));
}
public void Update(ProductDto productDto)
{
var product = Mapper.Map<Product>(productDto);
context.Entry(product).State = EntityState.Modified;
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public interface IProductRepository : IDisposable
{
IEnumerable<ProductDto> GetProducts { get; }
ProductDto GetProduct(int productId);
void Update(ProductDto productDto);
void Save();
}
Then in my Controller I'm using the repositories as so:
public class HomeController : Controller
{
private readonly IBookingRepository bookingRepository;
private readonly IProductRepository productRepository;
public HomeController() : this(new BookingRepository(), new ProductRepository()) { }
public HomeController(IBookingRepository bookingRepository, IProductRepository productRepository)
{
this.bookingRepository = bookingRepository;
this.productRepository = productRepository;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing && this.bookingRepository != null)
this.bookingRepository.Dispose();
if (disposing && this.productRepository != null)
this.productRepository.Dispose();
}
}
So now I'm hoping to create a Unit Of Work to abstract these repositories and share the context and also create a generic repository for the duplicated actions (Save and Update) bearing in mind I'm passing in Dtos and Mapping to Entity objects. I'm having difficulty understanding how to knit it all together.
Additionally, I've seen this post
Repository pattern with generics and DI
which states "You should not have other repository interfaces besides your generic repository" and that custom queries "deserve their own (generic) abstraction:" which is adding another complication to my overworked brain as my repositories will have custom queries that return complex linked objects using Include Statements as Lazy Loading is disabled.
So I'm prepared to be shot down and told that I'm going about this the wrong way but would be grateful for any direction given.
Thanks in advance.
Don't use generic repositories. They are all leaky abstractions. Ask yourself, what benefit to you get by using an abstraction that doesn't really abstract away something? You could use your OR/M directly in those cases.
What I means is that anything that exposes IQueryable<T> forces the user to learn about the weaknesses that the underlying OR/M has. Examples: How do the orm handle lazy loading? How do I eagerly load related entities? How do I create a IN clause?
If you truly want to use the repository pattern either use it together with the specification pattern (you can keep on using a generic repository then) or create repositories that are specific for each root aggregate.
I've blogged about it: http://blog.gauffin.org/2013/01/repository-pattern-done-right/
What I usually do in this case is to create a Base abstract Repository class like this:
public abstract class BaseRepository<T> : IRepository<T>
{
Entities context = new Entities();
public virtual T GetAll()
{
return context.Set<T>();
}
// Add base implementation for normal CRUD here
}
If you don't need special queries then you don't need to create special interface and classes (but you can of course, to improve readability). So you will use, for example:
var bookingsRepo = new BaseRepository<BookingsDto>();
var allBookings = bookingsRepo.GetAll();
If you need some special queries, you create an interface that extends the base interface:
public interface IProductRepository : IRepository<Product>
{
Product GetSpecialOffer();
}
Then create your class:
public class ProductRepository : BaseRepository<Product>, IProductRepository
{
public Product GetSpecialOffer()
{
// your logic here
}
}
That way you only specify a minimal number of special cases while relying on the Base abstract implementation for all things normal.
I added virtual to the base methods because I always like to give derived class the ability to override stuff...

How to pass constructor arguments to ninjectcontrollerfactory in asp.net mvc DI

I am working on asp.net mvc 4. I am trying to implement dependeny injection using ninject and repository pattern with code first model.
IMessageRepository
public interface IMessageRepository
{
void IsMessageRead();
}
MessageRepository
public class MessageRepository:IMessageRepository
{
string id="";
public MessageRepository(string idparam)
{
id=idparam;
}
EFMsgContext context=new EFMsgContext(id);
public void IsMessageRead()
{
...
}
}
EFMsgContext
public class EFMsgContext:Dbcontext
{
public EFMsgContext(string id):base("MyContext")
{
//based on id i will construct a connection string from my database.
}
....
}
my controller
public class MYController:Controller
{
private IMessageRepository repo;
public MYController(IMessageRepository repoparam)
{
repo=repoparam;
}
public ActionResult Index()
{
repo.IsMessageRead();
}
}
and i am using Ninject for dependency injection i bind my interface with concrete class like,
ninjectKernel.Bind<IMessageRepository>().To<MessageRepository>();
here how could i pass constructor parameters to the binding and is there any way to write the logic for buidling connection string inside the ninjectcontrollerfactory. please guide me.
You have to use the WithConstructorArgument extension method
ninjectKernel.Bind<IMessageRepository>().To<MessageRepository>().WithConstructorArgument("idparam", value);
You can even pass a Func as a second argument.
ninjectKernel.Bind<IMessageRepository>().To<MessageRepository>()
.WithConstructorArgument("idparam", (c) => {
// read from somewhere and return
});

Mocking a DataServiceQuery<TElement>

How can I mock a DataServiceQuery for unit testing purpose?
Long Details follow:
Imagine an ASP.NET MVC application, where the controller talks to an ADO.NET DataService that encapsulates the storage of our models (for example sake we'll be reading a list of Customers). With a reference to the service, we get a generated class inheriting from DataServiceContext:
namespace Sample.Services
{
public partial class MyDataContext : global::System.Data.Services.Client.DataServiceContext
{
public MyDataContext(global::System.Uri serviceRoot) : base(serviceRoot) { /* ... */ }
public global::System.Data.Services.Client.DataServiceQuery<Customer> Customers
{
get
{
if((this._Customers==null))
{
this._Customers = base.CreateQuery<Customer>("Customers");
}
return this._Customers;
}
}
/* and many more members */
}
}
The Controller could be:
namespace Sample.Controllers
{
public class CustomerController : Controller
{
private IMyDataContext context;
public CustomerController(IMyDataContext context)
{
this.context=context;
}
public ActionResult Index() { return View(context.Customers); }
}
}
As you can see, I used a constructor that accepts an IMyDataContext instance so that we can use a mock in our unit test:
[TestFixture]
public class TestCustomerController
{
[Test]
public void Test_Index()
{
MockContext mockContext = new MockContext();
CustomerController controller = new CustomerController(mockContext);
var customersToReturn = new List<Customer>
{
new Customer{ Id=1, Name="Fred" },
new Customer{ Id=2, Name="Wilma" }
};
mockContext.CustomersToReturn = customersToReturn;
var result = controller.Index() as ViewResult;
var models = result.ViewData.Model;
//Now we have to compare the Customers in models with those in customersToReturn,
//Maybe by loopping over them?
foreach(Customer c in models) //*** LINE A ***
{
//TODO: compare with the Customer in the same position from customersToreturn
}
}
}
MockContext and MyDataContext need to implement the same interface IMyDataContext:
namespace Sample.Services
{
public interface IMyDataContext
{
DataServiceQuery<Customer> Customers { get; }
/* and more */
}
}
However, when we try and implement the MockContext class, we run into problems due to the nature of DataServiceQuery (which, to be clear, we're using in the IMyDataContext interface simply because that's the data type we found in the auto-generated MyDataContext class that we started with). If we try to write:
public class MockContext : IMyDataContext
{
public IList<Customer> CustomersToReturn { set; private get; }
public DataServiceQuery<Customer> Customers { get { /* ??? */ } }
}
In the Customers getter we'd like to instantiate a DataServiceQuery instance, populate it with the Customers in CustomersToReturn, and return it. The problems I run into:
1~ DataServiceQuery has no public constructor; to instantiate one you should call CreateQuery on a DataServiceContext; see MSDN
2~ If I make the MockContext inherit from DataServiceContext as well, and call CreateQuery to get a DataServiceQuery to use, the service and query have to be tied to a valid URI and, when I try to iterate or access the objects in the query, it will try and execute against that URI. In other words, if I change the MockContext as such:
namespace Sample.Tests.Controllers.Mocks
{
public class MockContext : DataServiceContext, IMyDataContext
{
public MockContext() :base(new Uri("http://www.contoso.com")) { }
public IList<Customer> CustomersToReturn { set; private get; }
public DataServiceQuery<Customer> Customers
{
get
{
var query = CreateQuery<Customer>("Customers");
query.Concat(CustomersToReturn.AsEnumerable<Customer>());
return query;
}
}
}
}
Then, in the unit test, we get an error on the line marked as LINE A, because http://www.contoso.com doesn't host our service. The same error is triggered even if LINE A tries to get the number of elements in models.
Thanks in advance.
I solved this by creating an interface IDataServiceQuery with two implementations:
DataServiceQueryWrapper
MockDataServiceQuery
I then use IDataServiceQuery wherever I would have previously used a DataServiceQuery.
public interface IDataServiceQuery<TElement> : IQueryable<TElement>, IEnumerable<TElement>, IQueryable, IEnumerable
{
IDataServiceQuery<TElement> Expand(string path);
IDataServiceQuery<TElement> IncludeTotalCount();
IDataServiceQuery<TElement> AddQueryOption(string name, object value);
}
The DataServiceQueryWrapper takes a DataServiceQuery in it's constructor and then delegates all functionality to the query passed in. Similarly, the MockDataServiceQuery takes an IQueryable and delegates everything it can to the query.
For the mock IDataServiceQuery methods, I currently just return this, though you could do something to mock the functionality if you want to.
For example:
// (in DataServiceQueryWrapper.cs)
public IDataServiceQuery<TElement> Expand(string path)
{
return new DataServiceQueryWrapper<TElement>(_query.Expand(path));
}
// (in MockDataServiceQuery.cs)
public IDataServiceQuery<TElement> Expand(string path)
{
return this;
}
[Disclaimer - I work at Typemock]
Have you considered using a mocking framework?
You can use Typemock Isolator to create a fake instance of DataServiceQuery:
var fake = Isolate.Fake.Instance<DataServiceQuery>();
And you can create a similar fake DataServiceContext and set it's behavior instead of trying to inherit it.

Resources