Castle Windsor resolve ienumerable and name - c#

I'm new to Castle Windsor (actually to DI) and trying to solve a scenario using windsor and i'm kind of stuck. To give an idea, there are 2 different remote sources from where I need to get some order info for a given customer no on the first attempt which is bit time consuming. The order info will never change in the future hence i would like to store that data in my local database for any subsequent use(s) which will increase the performance of my application.
It seems like the decorator pattern is a good candidate for this and below is my initial attempt.
public interface IOrderRepository
{
IEnumerable<OrderInfo> Get(string customerNo);
void Save(string customerNo, IEnumerable<OrderInfo> orders);
}
public class RealTimeRepo1 : IOrderRepository
{
public IEnumerable<OrderInfo> Get(string customerNo)
{
/// Fetch the data from remote source 1
}
public void Save(string customerNo, IEnumerable<OrderInfo> orders)
{
/// You cannot update the order info in remote source
throw new NotImplementedException();
}
}
public class RealTimeRepo2 : IOrderRepository
{
public IEnumerable<OrderInfo> Get(string customerNo)
{
/// Fetch the data from remote source 2
}
public void Save(string customerNo, IEnumerable<OrderInfo> orders)
{
/// You cannot update the order info in remote source
throw new NotImplementedException();
}
}
public LocalOrderRepo : IOrderRepository
{
public IEnumerable<OrderInfo> Get(string customerNo)
{
/// Fetch the data from local data source
}
public void Save(string customerNo, IEnumerable<OrderInfo> orders)
{
/// Save the data on local data source
}
}
public CacheOrderRepo : IOrderRepository
{
private readonly IEnumerable<IOrderRepository> realTimeRepos;
private readonly IOrderRepository localRepo;
public CacheOrderRepo(IEnumerable<IOrderRepository> realTime, IOrderRepository localRepo)
{
this.realTimeRepos = realTime;
this.localRepo = localRepo;
}
public IEnumerable<OrderInfo> Get(string customerNo)
{
List<OrderInfo> orders = this.localRepo.Get(customerNo);
if(orders == null) && (!orders.Any()
{
foreach(var r in this.realTimeRepos)
{
List<OrderInfo> t = r.Get(customerNo);
if(t.Any())
{
orders.AddRange(t);
}
}
if(orders.Any())
{
this.localRepo.save(customerNo, orders);
}
}
return orders;
}
public void Save(string customerNo, IEnumerable<OrderInfo> orders)
{
/// Save the data on local data source
}
}
I hope the above code snippet gives an idea. My struggle is how to register this using windsor.
//regsiter
this._container.Kernal.Resolver.AddSubResolver(new
CollectionResolver(this._container.Kenrnal));
this._container.Register(
Component.For<IOrderRepository>.ImplementedBy<RealTimeRepo1>().LifeStyle.Transient,
Component.For<IOrderRepository>.ImplementedBy<RealTimeRepo2>().LifeStyle.Transient
);
Using the collection subresolver i was able to register an ienumerable of RealTime repos 1 & 2. How i should register the local repo (i.e. my constructor parameter 2)?
Appreciate your help. I'm also open for suggestions with my understanding of the decorator pattern or castle windsor...

Firstly you will need to register the CollectionResolver.
Secondly I suggest you either change the constructor of CacheOrderRepo to explicitly reference LocalOrderRepo or define a different abstraction (e.g. ILocalOrderRepo) for it.
public class CacheOrderRepo : IOrderRepository
{
private readonly IEnumerable<IOrderRepository> realTimeRepos;
private readonly LocalOrderRepo localRepo;
public CacheOrderRepo(IEnumerable<IOrderRepository> realTime, LocalOrderRepo localRepo)
{
this.realTimeRepos = realTime;
this.localRepo = localRepo;
}
The registration is then done by registering the composite (CacheOrderRepo) first, like this:
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
container.Register(
Component.For<IOrderRepository>().ImplementedBy<CacheOrderRepo>(),
Component.For<IOrderRepository>().ImplementedBy<RealTimeRepo1>(),
Component.For<IOrderRepository>().ImplementedBy<RealTimeRepo2>(),
Component.For<LocalOrderRepo>().ImplementedBy<LocalOrderRepo>());
var service = container.Resolve<IOrderRepository>();
Assert.IsInstanceOf<CacheOrderRepo>(service);

Related

Autofac SingleInstance WebApi Performance

We've improved the performance of our API's adding services without state to .SingleInstance() , but I've a question, regarding the demo code attached,
The IBusAppService that we are using on the controller is set to SingleInstance(), but inside the BusAppService, we are using more Interfaces, for example ( IBusRepository or IBusDomainService )
So the question is, in order to increase the performnace, should we set all interfaces to SingleInstance() inside the IBusAppService or the performance is the same because they are inside a SingleInstance??
I'll attach here some code with the workflow :
The ApiController:
public class BusApiController : ApiController
{
private readonly IBusAppService _iBusAppService;
private readonly IBusMapper _iBusMapper;
public BusApiController(IBusAppService iBusAppService,
IBusMapper iBusMapper)
{
_iBusAppService = iBusAppService;
_iBusMapper = iBusMapper;
}
[HttpGet]
public BusResponse Get(long id)
{
var bus = _iBusAppService.Get(id);
var busResponse = _iBusMapper.Convert(bus);
return busResponse;
}
}
public class BusResponse {
public long Id { get; set; }
}
public interface IBusMapper
{
BusResponse Convert(Bus bus);
}
public class BusMapper : IBusMapper
{
public BusResponse Convert(Bus bus)
{
if (bus == null) return null;
var result = new BusResponse{Id = bus.Id};
return result;
}
}
builder.RegisterType<BusAppService>().As<IBusAppService>().SingleInstance();
builder.RegisterType<BusMapper>().As<IBusMapper>().SingleInstance();
The ApplicationService
public interface IBusAppService
{
Bus Get(long id);
}
public class BusAppService : IBusAppService
{
private readonly IBusRepository _iBusRepository;
private readonly IBusDomainService _iBusDomainService;
public BusAppService(IBusRepository iBusRepository, IBusDomainService iBusDomainService )
{
_iBusRepository = iBusRepository;
_iBusDomainService = iBusDomainService;
}
public Bus Get(long id)
{
var bus = this._iBusRepository.Get(id);
var busTax = this._iBusDomainService.CalculateTax(bus);
var result = bus;
return result;
}
}
Anything consumed by a single instance service will end up being single instance due to captive dependencies. You could change them to be single instance, too, but it won't necessarily change the performance related to instantiation cost that you see now.

Making an application Database Agnostic

I have an existing C# application, which I intend to make Database Agnostic, in such a way that the Database Engine is abstracted from the Business Logic completely.
Here is my approach to make one -
public abstract class DbEngine // I can also make it an Interface
{
}
public class SQLDBEngine : DbEngine
{
public bool ExecuteSP(string SPName)
{
}
public void ExecuteInlineQuery(String SQLQuery)
{
}
}
public class MySQLDBEngine : DbEngine
{
public bool ExecuteSP(string SPName)
{
}
public void ExecuteInlineQuery(String SQLQuery)
{
}
}
I then have a Factory class, which takes care of Instantiating the appropriate DbEngine object -
public class ConnectionManager
{
string CurrentEngine;
public ConnectionManager()
{
// Read from configuration file to know which database to configure
// Config returns wither MS or MY
// MS = SQLDBEngine
// MY = MYSQLDBEngine
}
public DbEngine GetDBInstance()
{
switch(CurrentEngine)
{
case "MS":
return new SQLDBEngine();
case "MY":
return new MySQLDBEngine();
default:
return new SQLDBEngine();
}
}
}
The Business Logic will only interact with the ConnectionManager object, thus abstracting the Database completely from it .
The Client will interact with the following code-
ConnectionManager conn = new ConnectionManager();
DBEngine obj = conn.GetDBInstance();
obj.ExecuteInlineQuery("select * from tblItems");
The Problem here, is that if the we introduce MongoDBEngine as the new database engine, this will require once more class MongoDBEngine - but since it doesn't have a Stored Procedure like feature, so ExecuteSP doesn't make sense and hence the Business Logic call will fail.
Iam just trying to encapsulate the Database Engine from the Business Logic, so that when the database is changed, the Business Logic should not undergo any change.
Is there any design pattern or technique that I could follow ?
Rather than trying to expose the functionality of the database to the application, you should abstract away the method of access. Instead of providing an ability to execute a query, embed that query or stored procedure call or insert/update/delete command as part of your repository class.
public class MySQLCustomerRepository : ICustomerRepository
{
private readonly string _connectionString;
public MySQLCustomerRepository(string connectionString)
{
_connectionString = connectionString;
}
public List<CustomerOrder> GetCustomerOrdersByDate(int customerId, DateTime startDate, DateTime endDate)
{
//open a MySQL connection and execute query to retrieve customer orders
}
}
public class MongoCustomerRepository : ICustomerRepository
{
private readonly string _connectionString;
public MongoCustomerRepository(string connectionString)
{
_connectionString = connectionString;
}
public List<CustomerOrder> GetCustomerOrdersByDate(int customerId, DateTime startDate, DateTime endDate)
{
//connect to mongo, get customers by running query
}
}
public interface ICustomerRepository
{
List<CustomerOrder> GetCustomerOrdersByDate(int customerId, DateTime startDate, DateTime endDate);
}
The consuming application itself should have no knowledge of queries, because the repository itself takes care of those details.
Part of the point of this is that each database will have different queries and commands that make sense for it. An SQL query written for MS SQL may not be the same as one written for Oracle, and of course SQL won't work at all on a no-SQL database. So each implementation should be responsible for using the correct interactions for its corresponding database, and your consuming application shouldn't need to know how that works, because it should always access the database via an interface, never through a concrete implementation .
I think the last answer from mason is a really step forward through a good desing. I would go one step further in OO desing and try to think as an object page for a Dto and return a sequence of something. A change i would do is to encapsulate the parameters of the methods inside the object and inject them through constructor, so this way you will have multiple clases implementing an abstraction of your query(1 class for a paged sequence, other class for searching for id, start and end time, etc. The result will be the same return type) instead of a big monster with a bunch of methods returning the same type. This way you get better mantainability, so if you have a issue with a mongo class for a specific query, you check one tiny class and not a GOD class, here is some paging desing:
/// <summary>
/// DTO
/// </summary>
public class CustomerOrder
{
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
/// <summary>
/// Define a contract that get a sequence of something
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IFetch<T>
{
IEnumerable<T> Fetch();
}
/// <summary>
/// Define a pageTemplate
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class PageTemplate<T> : IFetch<T>
{
protected readonly int pageSize;
protected readonly int page;
public PageTemplate(int page, int pageSize)
{
this.page = page;
this.pageSize = pageSize;
}
public abstract IEnumerable<T> Fetch();
}
/// <summary>
/// Design a MyDto Page object, Here you are using the Template method
/// </summary>
public abstract class MyDtoPageTemplate : PageTemplate<CustomerOrder>
{
public MyDtoPageTemplate(int page, int pageSize) : base(page, pageSize) { }
}
/// <summary>
/// You can use ado.net for full performance or create a derivated class of MyDtoPageTemplate to use Dapper
/// </summary>
public sealed class SqlPage : MyDtoPageTemplate
{
private readonly string _connectionString;
public SqlPage(int page, int pageSize, string connectionString) : base(page, pageSize)
{
_connectionString = connectionString;
}
public override IEnumerable<CustomerOrder> Fetch()
{
using (var connection = new SqlConnection(_connectionString))
{
//This can be injected from contructor or encapsulated here, use a Stored procedure, is fine
string commandText = "Select Something";
using (var command = new SqlCommand(commandText, connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
if (reader.HasRows) yield break;
while (reader.Read())
{
yield return new CustomerOrder()
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
Value = reader.GetString(2)
};
}
}
}
}
}
}
public sealed class MongoDbPage : MyDtoPageTemplate
{
private readonly string _connectionString;
public MongoDbPage(int page, int pageSize, string connectionString) : base(page, pageSize)
{
_connectionString = connectionString;
}
public override IEnumerable<CustomerOrder> Fetch()
{
//Return From CustomerOrder from mongoDb
throw new NotImplementedException();
}
}
/// <summary>
/// You can test and mock the fetcher
/// </summary>
public sealed class TestPage : IFetch<CustomerOrder>
{
public IEnumerable<CustomerOrder> Fetch()
{
yield return new CustomerOrder() { Id = 0, Name = string.Empty, Value = string.Empty };
yield return new CustomerOrder() { Id = 1, Name = string.Empty, Value = string.Empty };
}
}
public class AppCode
{
private readonly IFetch<CustomerOrder> fetcher;
/// <summary>
/// From IoC, inject a fetcher object
/// </summary>
/// <param name="fetcher"></param>
public AppCode(IFetch<CustomerOrder> fetcher)
{
this.fetcher = fetcher;
}
public IEnumerable<CustomerOrder> FetchDtos()
{
return fetcher.Fetch();
}
}
public class CustomController
{
private readonly string connectionString;
public void RunSql()
{
var fetcher = new SqlPage(1, 10, connectionString);
var appCode = new AppCode(fetcher);
var dtos = appCode.FetchDtos();
}
public void RunTest()
{
var fetcher = new TestPage();
var appCode = new AppCode(fetcher);
var dtos = appCode.FetchDtos();
}
}

Changing database at runtime with MVC WebApi 2

I want to change the connection to a database at runtime in a REST Api. I want to put a variable of the request and let the Api decide which connectionstring to use.
For example:
I put the variable "dbid" with the value "develop" in the request header and send it to the Api.
The Api sees the header and gets the correct connectionstring from the web.config.
I have three layers (data, business, api). The data contains EntityFramework to get and set data. Like this:
public class WebsiteContext : IocDbContext, IWebsites
{
public DbSet<Website> Websites { get; set; }
public IEnumerable<Website> GetAll()
{
return Websites.ToList();
}
}
(IoCDbContext.cs)
public class IocDbContext : DbContext, IDbContext
{
public IocDbContext() : base("develop")
{
}
public void ChangeDatabase(string connectionString)
{
Database.Connection.ConnectionString= connectionString;
}
}
In the business I have a class to retrieve data from the datalayer and do some logical stuff (not needed here, but still good for the story).
public class Websites : IWebsites
{
private readonly Data.Interfaces.IWebsites _websiteContext;
#region Constructor
public Websites(Data.Interfaces.IWebsites websiteContext)
{
_websiteContext = websiteContext;
}
#endregion
#region IWebsites implementation
public IEnumerable<Website> GetWebsites()
{
List<Data.Objects.Website> websiteDtos = _websiteContext.GetAll().ToList();
return websiteDtos.Select(web => web.ToModel()).ToList();
}
#endregion
}
public static class WebsiteMapper
{
public static Website ToModel(this Data.Objects.Website value)
{
if (value == null)
return null;
return new Website
{
Id = value.Id,
Name = value.Name
};
}
}
And, last but not least, the controller:
public class WebsiteController : ApiController
{
private readonly IWebsites _websites;
public WebsiteController(IWebsites websites)
{
_websites = websites;
}
public IEnumerable<Website> GetAll()
{
return _websites.GetWebsites().ToList();
}
}
My Unity configuration:
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<Business.Interfaces.IWebsites, Websites>();
container.RegisterType<IDbContext, IocDbContext>();
container.RegisterType<IWebsites, WebsiteContext>();
// e.g. container.RegisterType<ITestService, TestService>();
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
So as you can see the connection string with the name "develop" is used by default. This will return a website with the name "website". Now I would change the header variable "dbid" to "live". The api should see this and should get the connectionstring that corresponds with the name "live". This last part is something I am trying, but nothing works.
This I tried:
Adding session to webapi. This means I break the stateless idea of REST api: not done
Statics cannot work either, because everyone could get the same connectionstring, but its user specific
Google, but most of the examples don't work for me
Searching StackOverflow... See previous point.
This is driving me crazy! There should be a way to change the connectionstring given by a value in a request header, right?
I have the same scenario in a multi-tenant application I created where I use a different connection string for each tenant.
It doesn't matter the implementation you choose, but you have to determine how you are going to differentiate each request per connection string. In my application, I created a custom route value, and used it in the url to differentiate each request. The important thing is to create whatever this mechanism is, and it needs to be the 1st thing you register in your DI framework, on a per request basis.
For example (using Ninject):
private static void RegisterServicdes(IKernel kernel)
{
kernel.Bind<ISiteContext>().To<SiteContext>().InRequestScope();
kernel.Bind<IDbContextFactory>().To<DbContextFactory>().InRequestScope();
// register other services...
}
Rather than your implementation of your DbContext, I would change to be this, then always create your DbContext instance via a DbContextFactory.
public class IocDbContext : DbContext, IDbContext
{
public IocDbContext(string connectionStringType) : base(connectionStringType) { }
}
Then you need to create a DbContextFactory that you use when you create your DbContext, and take the above class as a dependency. Or you can take the dependency into your services, and pass it into the DbContextFactory instead.
public interface IDbContextFactory
{
TestModel CreateContext();
}
public class DbContextFactory : IDbContextFactory
{
private string _siteType;
public DbContextFactory(ISiteContext siteContext)
{
_siteType = siteContext.Tenant;
}
public TestModel CreateContext()
{
return new TestModel(FormatConnectionStringBySiteType(_siteType));
}
// or you can use this if you pass the IMultiTenantHelper dependency into your service
public static TestModel CreateContext(string siteName)
{
return new TestModel(FormatConnectionStringBySiteType(siteName));
}
private static string FormatConnectionStringBySiteType(string siteType)
{
// format from web.config
string newConnectionString = #"data source={0};initial catalog={1};integrated security=True;MultipleActiveResultSets=True;App=EntityFramework";
if (siteType.Equals("a"))
{
return String.Format(newConnectionString, #"(LocalDb)\MSSQLLocalDB", "DbOne");
}
else
{
return String.Format(newConnectionString, #"(LocalDb)\MSSQLLocalDB", "DbTwo");
}
}
}
Then you can use it like so when accessing your DbContext:
public class DbAccess
{
private IDbContextFactory _dbContextFactory;
public DbAccess(IDbContextFactory dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public void DoWork()
{
using (IocDbContext db = _dbContextFactory.CreateContext())
{
// use EF here...
}
}
}
ISiteContext interface implementation (for using route).
public interface ISiteContext
{
string Tenant { get; }
}
public class SiteContext : ISiteContext
{
private const string _routeId = "tenantId";
private string _tenant;
public string Tenant { get { return _tenant; } }
public SiteContext()
{
_tenant = GetTenantViaRoute();
}
private string GetTenantViaRoute()
{
var routedata = HttpContext.Current.Request.RequestContext.RouteData;
// Default Routing
if (routedata.Values[_routeId] != null)
{
return routedata.Values[_routeId].ToString().ToLower();
}
// Attribute Routing
if (routedata.Values.ContainsKey("MS_SubRoutes"))
{
var msSubRoutes = routedata.Values["MS_SubRoutes"] as IEnumerable<IHttpRouteData>;
if (msSubRoutes != null && msSubRoutes.Any())
{
var subRoute = msSubRoutes.FirstOrDefault();
if (subRoute != null && subRoute.Values.ContainsKey(_routeId))
{
return (string)subRoute.Values
.Where(x => x.Key.Equals(_routeId))
.Select(x => x.Value)
.Single();
}
}
}
return string.Empty;
}
}
API action:
[Route("api/{tenantId}/Values/Get")]
[HttpGet]
public IEnumerable<string> Get()
{
_testService.DoDatabaseWork();
return new string[] { "value1", "value2" };
}
you need to create a factory class for Dynamic picking of connection string.
It is the responsibility of that class to give correct connectionString based on the certain Parameter.

Shared services in Repository Pattern

I am wondering how to deal with a situation when inside one service lets say ICompanyService I need to call another method from IUserAccountService. ?
So generally lets say that a Company shouldn't exist without an UserAccount.
The IUserAccount implementation service class looks like this:
public class UserAccountService : CrudService<UserAccount>, IUserAccountService
{
private readonly IRepository<UserAccount> _userAccountRepository;
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
public CompanyService(IRepository<UserAccount> userAccountRepository,
IUnitOfWorkFactory unitOfWorkFactory)
: base(userAccountRepository, unitOfWorkFactory)
{
_userAccRepository = userAccRepository;
}
public int RegisterUser(UserAccount user) {
using (var uow=_unitOfWorkFactory.Create())
{
// Details omitted for brievity
var userId = _userAccountRepository.Create(user);
uow.Commit();
return userId;
}
}
//Other service methods
}
The company ICompanyService implementation:
public class CompanyService : CrudService<Company>, ICompanyService
{
private readonly IRepository<Company> _companyRepository;
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
public CompanyService(IRepository<Company> companyRepository,
IUnitOfWorkFactory unitOfWorkFactory)
: base(companyRepository, unitOfWorkFactory)
{
_companyRepository= companyRepository;
}
public int CreateCompanyWithUserAccount(Company company) {
using (var uow=_unitOfWorkFactory.Create())
{
// Some validation with the company.Details omitted for brievity
// Here I need an instance of IUserAccountService
// Suppose I get it through DI or IoC
var userAccountService = IoC.Resolve<IUserAccountService>();
### // Is such approach good or bad?! ###
var userId = userAccountService.RegisterUser(company.UserAccount);
// Map the user id to the company
company.UserAccount.Id = userId;
var companyId = _companyRepository.Create(company);
uow.Commit();
return companyId;
}
}
//Other service methods
}
ORM under the repository is: NHibernate
Seems you have wrong constructor in UserAccountService implementations: public CompanyService
In CompanyService implementation, you better resolve IUserAccountService dependency right in a constructor, so you do it once per object creation, not each time you call method.
There's no problems with those dependencies. If two objects of IUnitOfWorkFactory implementations are problem -> make a singleton
You could just take a dependency on the IRepository<UserAccount>:
public class CompanyService : CrudService<Company>, ICompanyService
{
private readonly IRepository<Company> _companyRepository;
private readonly IRepository<UserAccount> _userAccountRepository;
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
public CompanyService(IRepository<Company> companyRepository,
IUnitOfWorkFactory unitOfWorkFactory
IRepository<UserAccount> userAccountRepository)
: base(companyRepository, unitOfWorkFactory)
{
_companyRepository= companyRepository;
_userAccountRepository = userAccountRepository;
}
public int CreateCompanyWithUserAccount(Company company) {
using (var uow=_unitOfWorkFactory.Create())
{
// Some validation with the company.Details omitted for brievity
var userId = _userAccountRepository.Create(company.UserAccount);
// Map the user id to the company
company.UserAccount.Id = userId;
var companyId = _companyRepository.Create(company);
uow.Commit();
return companyId;
}
}
//Other service methods
}
IMO, it's better to take a dependency on the repository. After all your company service is creating a company and it needs to do some work in the database, which is what the repositories are for. From what I can see in the code, there's no need to involve the UserAccountService.

Should I inject ServiceStack's ICacheManager?

I'm looking to implement a caching tier in our application and accidentally came across ServiceStack's ICacheManager.
ICacheManager.Resolve looks as though it's exactly what I'm after (try and get, if it's not in the cache then call the function to get and store it). All documentation I can find however is about using ICacheClient.
How I can wire up ICacheManager using AutoFac? I assume I need to wire up a client e.g.:
_builder.Register(c => new MemoryCacheClient())
.As<ICacheClient>();
But then I'm not sure what ICacheManager should resolve to.
Is this a good idea or am I abusing ServiceStack?
I've added a custom cache manager for the time being but it feels wrong for some reason:
public class CacheManager : ICacheManager
{
public CacheManager(ICacheClient cacheClient)
{
CacheClient = cacheClient;
}
public void Clear(IEnumerable<string> cacheKeys)
{
Clear(cacheKeys.ToArray());
}
public void Clear(params string[] cacheKeys)
{
CacheClient.ClearCaches(cacheKeys.ToArray());
}
public ICacheClient CacheClient { get; private set; }
public T Resolve<T>(string cacheKey, Func<T> createCacheFn) where T : class
{
return Resolve(cacheKey, new TimeSpan(0, 15, 0), createCacheFn);
}
public T Resolve<T>(string cacheKey, TimeSpan expireIn, Func<T> createCacheFn) where T : class
{
var cacheResult = CacheClient.Get<T>(cacheKey);
if (cacheResult != null)
return cacheResult;
var item = createCacheFn();
CacheClient.Set(cacheKey, item, expireIn);
return item;
}
}

Categories

Resources