using Erp.Controllers;
using DryIoc;
using System;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Linq;
namespace Erp
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var ioc = new DryIocDependencyResolver();
ControllerBuilder.Current.SetControllerFactory(ioc);
}
}
class DryIocDependencyResolver : System.Web.Mvc.DefaultControllerFactory
{
DryIoc.Container _container;
public DryIocDependencyResolver()
{
_container = new DryIoc.Container();
RegisterTheIocs();
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
System.Web.Mvc.IController ic = controllerType == null
? null
: (System.Web.Mvc.IController)_container.Resolve(controllerType);
// _container.ResolvePropertiesAndFields(ic); // uncomment this if you want to use DI on controller's properties
return ic;
}
void RegisterTheIocs()
{
// ISessionFactory definition
System.Reflection.Assembly assembly = typeof(HomeController).Assembly;
foreach (var controller in assembly.GetTypes().Where(t => typeof(Controller).IsAssignableFrom(t)))
{
_container.Register(controller, DryIoc.Reuse.InResolutionScope);
}
// _container.Register(typeof(Elmah.Mvc.ElmahController), DryIoc.Reuse.InResolutionScope);
// http://www.ienablemuch.com/2013/11/typical-nhibernate-sessionfactory.html
_container.RegisterDelegate<NHibernate.ISessionFactory>(x => Erp.DomainMapping.Mapper.SessionFactory, DryIoc.Reuse.Singleton);
_container.Register<UnitTestFriendlyDal.IDataStore, UnitTestFriendlyDal.DataStore>(DryIoc.Reuse.InResolutionScope);
}
}
}
Sample Controller, we need to call _ds.Dispose() to effect the transaction:
using Erp.Domain.TheModels;
using Erp.Dto.Dtos;
using UnitTestFriendlyDal;
using System.Web.Mvc;
namespace Erp.Controllers
{
public class CompaniesController : Controller
{
IDataStore _ds;
public CompaniesController(IDataStore ds)
{
_ds = ds;
}
public ViewResult Summary(int id = 0)
{
var company = _ds.Get<company>(id);
var companyDto = company.Summary(_ds);
return View(companyDto);
}
public ViewResult Search(SearchedCompanyDto sc)
{
Company.SearchCompanies(_ds, sc);
return View(sc);
}
protected override void Dispose(bool disposing)
{
_ds.Dispose();
base.Dispose(disposing);
}
}
}
IDataStore definition:
using System;
using System.Linq;
using NHibernate.Linq;
namespace UnitTestFriendlyDal
{
public interface IDataStore : IDisposable
{
IQueryable<T> Query<T>();
T Get<T>(object id);
T Load<T>(object id);
object Save(object transientObject);
}
public class DataStore : IDataStore
{
NHibernate.ISessionFactory _sessionFactory;
NHibernate.ISession _session;
NHibernate.ITransaction _transaction;
public DataStore(NHibernate.ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
_session = _sessionFactory.OpenSession();
_transaction = _session.BeginTransaction();
}
IQueryable<T> IDataStore.Query<T>()
{
return _session.Query<T>();
}
T IDataStore.Get<T>(object id)
{
return _session.Get<T>(id);
}
T IDataStore.Load<T>(object id)
{
return _session.Load<T>(id);
}
object IDataStore.Save(object transientObject)
{
return _session.Save(transientObject);
}
// Because transaction is a cross-cutting concern. It should be automated
void IDisposable.Dispose()
{
// http://www.hibernatingrhinos.com/products/nhprof/learn/alert/donotuseimplicittransactions
_transaction.Commit();
_transaction.Dispose();
_session.Dispose();
}
}
/// <summary>
/// cross-cutting concern
/// MakeCacheable replaces Cacheable, so IQueryable detection provider can be done here
/// Can't use NHibernate's built-in .Cacheable on non-NHibernate IQueryable, it will throw an error
/// </summary>
public static class NHibernateLinqExtensionMethods
{
public static IQueryable<T> MakeCacheable<T>(this IQueryable<T> query)
{
if (query.Provider.GetType() == typeof(NHibernate.Linq.DefaultQueryProvider))
query = query.Cacheable();
return query;
}
}
}
Sample Domain Model:
using Erp.Dto.Dtos;
using UnitTestFriendlyDal;
using System.Linq;
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo("Erp.Domain.Test")]
namespace Erp.Domain.TheModels
{
// What is Anemic Domain Model
// http://en.wikipedia.org/wiki/Anemic_domain_model
// http://www.martinfowler.com/bliki/AnemicDomainModel.html
// this is a non-Anemic Domain Model
public class Company
{
// Use Virtuosity.Fody to eliminate the use of virtual keywords on NHibernate
// https://www.nuget.org/packages/Virtuosity.Fody/
// http://github.com/Fody/Virtuosity
public int CompanyId { get; protected internal set; }
public string CompanyName { get; protected internal set; }
public string CompanyUrl { get; protected internal set; }
public byte[] TinyLogo { get; protected internal set; }
public static void SearchCompanies(IDataStore ds, SearchedCompanyDto sc)
{
var q = from c in ds.Query<Company>().MakeCacheable()
where string.IsNullOrWhiteSpace(sc.q) || c.CompanyName.StartsWith(sc.q)
select c;
// http://www.ienablemuch.com/2014/10/proper-way-to-query-reference-entity.html
sc.Companies = q.ToList().Select(c => new CompanyDto { CompanyId = c.CompanyId, CompanyName = c.CompanyName, TinyLogo = c.TinyLogo });
}
// Just ready this parameter IDataStore,
// so if this one entity need information from another domain model(s) that is not in its navigable properties,
// it's easy to access those information
public CompanyDto Summary(IDataStore ds)
{
return new CompanyDto { CompanyName = this.CompanyName };
}
}
}
Sample Unit Test:
using Erp.Domain.TheModels;
using UnitTestFriendlyDal;
using Erp.Dto.Dtos;
using Moq;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Erp.Domain.Test
{
[TestClass]
public class UnitTest
{
[TestMethod]
public void Test_if_search_code_is_done()
{
// Arrange
var companies = new[] {
new Company { CompanyName = "Alpha" },
new Company { CompanyName = "Beta" },
new Company { CompanyName = "Delta" },
new Company { CompanyName = "Atlantis" },
}.AsQueryable();
var ds = new Mock<IDataStore>();
ds.Setup(x => x.Query<Company>()).Returns(companies);
// Act
var sc = new SearchedCompanyDto { q = "A" };
Company.SearchCompanies(ds.Object, sc);
// Assert
Assert.AreEqual(2, sc.Companies.Count());
}
}
}
Happy Coding!
No comments:
Post a Comment