I want to write many GET handlers that receive an ID for an object,
site.com/controller/Action1/1234
site.com/controller/Action2/1234
site.com/controller/Action3/1234
I would like to write the code that fetches the complex object from the DB just once:
class ComplexObject
{
public string str1 { get; set; }
public string str2 { get; set; }
}
ComplexObject GetFromId(string id)
{
ComplexObject x = Database.GetById(id);
if (x == null)
{
return Http404();
}
return x;
}
and then just use the object directly:
[Route("/[controller]/[action]/{message}")]
[HttpGet]
public string Action1(ComplexObject message)
{
return message.str1;
}
[Route("/[controller]/[action]/{message}")]
[HttpGet]
public string Action2(ComplexObject message)
{
return message.str1;
}
[Route("/[controller]/[action]/{message}")]
[HttpGet]
public string Action3(ComplexObject message)
{
return message.str1;
}
And that all of my handlers will just get the object, and won't have to check whether the ID is correct, etc.
How is that possible?
The official Microsoft Docs describe exactly how you can bind route parameters to a complex object from a database using a custom model binder.
Here's their example model binder:
public class AuthorEntityBinder : IModelBinder
{
private readonly AuthorContext _context;
public AuthorEntityBinder(AuthorContext context)
{
_context = context;
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var modelName = bindingContext.ModelName;
// Try to fetch the value of the argument by name
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value))
{
return Task.CompletedTask;
}
if (!int.TryParse(value, out var id))
{
// Non-integer arguments result in model state errors
bindingContext.ModelState.TryAddModelError(
modelName, "Author Id must be an integer.");
return Task.CompletedTask;
}
// Model will be null if not found, including for
// out of range id values (0, -3, etc.)
var model = _context.Authors.Find(id);
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
And then there are various ways to use this new model binder. One is to add an attribute on the model itself:
[ModelBinder(BinderType = typeof(AuthorEntityBinder))]
public class Author
{
// snip
}
Another is to use an attribute on the action parameters:
[HttpGet("{id}")]
public IActionResult GetById([ModelBinder(Name = "id")] Author author)
{
// snip
}
I am not sure why one would want to do what you are proposing, but it unnecessarily overcomplicates things and causes dependencies on the model binder.
Here is how I would implement this:
Have a class that manages your complex object and hide it behind an interface, the inject it into the controller:
public interface IComplexObjectManager
{
ComplexObject GetFromId(string id);
}
public class ComplexObjectManager : IComplexObjectManager
{
private readonly Database _database;
public ComplexObjectManager(Database database)
{
_database = database;
}
public ComplexObject GetFromId(string id)
{
ComplexObject x = _database.GetById(id);
return x;
}
}
[ApiController]
public class ComplexObjectController
{
public ComplexObjectController(IComplexObjectManager complexObjectManager)
{
ObjectManager = complexObjectManager;
}
public IComplexObjectManager ObjectManager { get; }
}
Then consume it in your method, changing the return type to an action result:
[Route("/[controller]/[action]/{id}")]
[HttpGet]
public IActionResult Action1(string id)
{
var obj = ObjectManager.GetFromId(id);
if(obj != null)
return Ok(obj.str1);
else
return NotFound();
}
Make sure to handle the response accordingly.
This approach decouples things (further abstraction can be added for Database), and allows for injection and unit testing.
Please check the code for consistency. I wrote this in a hurry.
I'm not doing the exactly thing that you are asking but i think it can help you. First of all, i'm using BaseController for it because you can filter your all actions before they are getting executed.
public class BaseController : Controller
{
#region /*IoC*/
public BaseViewModel baseViewModel;
public IUnitOfWork<Product> unitOfWorkProductForCart;
#endregion
#region /*ctor*/
public BaseController(IUnitOfWork<Product> unitOfWorkProductForCart)
{
this.unitOfWorkProduct = unitOfWorkProduct;
}
#endregion
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string controllerName = filterContext.ActionDescriptor.RouteValues["controller"];
string actionName = filterContext.ActionDescriptor.RouteValues["action"];
if (actionName == "ProductDetails")
{
var urlParameters = filterContext.ActionArguments;
if (urlParameters.Count != 0)
{
var isThatSlug = urlParameters.ElementAt(0).Key;
if (isThatSlug == "slug")
{
var slugCondition = urlParameters.ElementAt(0).Value;
var isThatProductExist = unitOfWorkProduct.RepositoryProduct.GetProductBySlugForChecking(slugCondition.ToString());
if (isThatProductExist.Count == 0)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary
{
{"controller","Account"},
{"action","NotFound"}
});
}
}
}
}
}
}
in that example, i'm controlling the parameters. if it's something like i don't want, it's redirects you to the NotFound page.
i hope it can give you a idea
Related
Presentation layer call a method (CreateEvent) in my application layer. This method use generic parameters :
public async Task<string> CreateEvent<T, TDocument>(T #event)
where T : class
where TDocument : Document
{
using (var scope = _serviceProvider.CreateScope())
{
var myRepository = scope.ServiceProvider.GetRequiredService<ICarrierEventRepository<TDocument>>();
var eventMapped = _mapper.Map<TDocument>(#event);
await myRepository.InsertOneAsync(eventMapped);
return eventMapped.Id.ToString();
}
}
Parameter T is object define in presentation layer and TDocument is abstract class that my entities (Domain layer) inherit.
public abstract class Document : IDocument
{
public ObjectId Id { get ; set ; }
//some other properties....
}
Example of entity :
public class PaackCollection : Document
{
public string ExternalId { get; set; }
public DateTime At { get; set; }
//some other properties....
}
In presentation layer, I call my CreateEvent method like this :
[HttpPost]
public async Task<IActionResult> Post(PayLoadPaackModel payLoadPaackModel)
{
var idCreated = await _carrierEventService.CreateEvent<PayLoadPaackModel, Domain.Entities.MongoDb.PaackCollection>(payLoadPaackModel);
//some code here....
return Ok("OK");
}
It's possible to use type of Domain.Entities.MongoDb.PaackCollection as parameter knowing that it belongs to the domain layer ? Normally presentation layer communicate only with application layer.
Thanks for advices
UPDATE
This solution works :
Call CreateEvent :
await _carrierEventService.CreateEvent(paackEventMapped);
public async Task<string> CreateEvent<T>(T #event)
where T : class
{
using (var scope = _serviceProvider.CreateScope())
{
Type typeParameterType = typeof(T);
if (typeParameterType.Equals(typeof(PaackEventDto)))
{
var eventMapped = _mapper.Map<PaackEvent>(#event);
var carrierEventRepository = scope.ServiceProvider.GetRequiredService<ICarrierEventRepository<PaackEvent>>();
await carrierEventRepository.InsertOneAsync(eventMapped);
return eventMapped.Id.ToString();
}
else if (typeParameterType.Equals(typeof(LaPosteEventDto)))
{
var eventMapped = _mapper.Map<LaposteEvent>(#event);
var carrierEventRepository = scope.ServiceProvider.GetRequiredService<ICarrierEventRepository<LaposteEvent>>();
await carrierEventRepository.InsertOneAsync(eventMapped);
return eventMapped.Id.ToString();
}
else
return default;
}
}
Is there another solution to use generic for avoid to have lot of condition to compare object ? Because I can have 50 differents objects...
UPDATE
I found solution to get the DestinationType for mapper :
var destinationMap = _mapper.ConfigurationProvider.GetAllTypeMaps().First(t => t.SourceType == typeParameterType);
var destType = destinationMap.DestinationType;
var eventMapped = _mapper.Map(#event, typeParameterType, destType);
It's working, now how I can get type of carrierEventRepository with destType ?
I try this var repository = typeof(ICarrierEventRepository<>).MakeGenericType(destType); but I can use method of my repository...
Here is another example where I am passing a Dto to my Api base class.
public async Task<ServiceResponse<TServiceResponce>> CreateAsyncServiceWrapper<TServiceResponce, TModelToCreate>(string url, TModelToCreate ModelToCreate)
{ Removed Code}
I am calling it like this
_serviceResponce = await _compRepo.CreateAsyncServiceWrapper<ServiceResponse<CompanyDto>, CreateCompanyDto>(StaticDetails.CompanyAPIPath, model);
Here is an example from one of my blogs.
/// <summary>
/// Create a new company Record.
/// </summary>
/// <param name="createCompanyDto"></param>
/// <returns></returns>
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CompanyDto))]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<CompanyDto>> CreateCompany([FromBody] CreateCompanyDto createCompanyDto)
{
if (createCompanyDto == null)
{
return BadRequest(ModelState);
}
if (!ModelState.IsValid) { return BadRequest(ModelState); }
var _newCompany = await _companyService.AddCompanyAsync(createCompanyDto);
if (_newCompany.Success == false && _newCompany.Message == "Exist")
{
return Ok(_newCompany);
}
if (_newCompany.Success == false && _newCompany.Message == "RepoError")
{
ModelState.AddModelError("", $"Some thing went wrong in respository layer when adding company {createCompanyDto}");
return StatusCode(500, ModelState);
}
if (_newCompany.Success == false && _newCompany.Message == "Error")
{
ModelState.AddModelError("", $"Some thing went wrong in service layer when adding company {createCompanyDto}");
return StatusCode(500, ModelState);
}
//Return new company created
return CreatedAtRoute("GetCompanyByGUID", new { CompanyGUID = _newCompany.Data.GUID }, _newCompany);
}
I finally found solution :
To get destination type with Automapper, I use _mapper.ConfigurationProvider.GetAllTypeMaps(), MakeGenericType help me to have my ICarrierEventRepository<T> and with this Post help me to use dynamic keyword for call method InsertOneAsync.
public async Task<string> CreateEvent<T>(T #event)
where T : class
{
using (var scope = _serviceProvider.CreateScope())
{
//Get destination type
Type typeParameterType = typeof(T);
var destinationMap = _mapper.ConfigurationProvider.GetAllTypeMaps().First(t => t.SourceType == typeParameterType);
var destType = destinationMap.DestinationType;
//Map with destination type
var eventMapped = _mapper.Map(#event, typeParameterType, destType);
//Get repository register in services
var repository = typeof(ICarrierEventRepository<>).MakeGenericType(destType);
dynamic repo = scope.ServiceProvider.GetRequiredService(repository);
//Insert on database
await repo.InsertOneAsync((dynamic)eventMapped);
//Get generate id
return ((dynamic)eventMapped).Id.ToString();
}
}
I was following the below link to get the validations done at Service Layer
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/models-data/validating-with-a-service-layer-cs
I ended up having cyclic dependency. So remove dependency injection of validation/ModelStateWrapper and used Initialize static way.
Brief Explanation about the Project: I have API, Services Layer, Repository, Database. I am using Automapper to map DTO's to Entities.
Controller:
public StudentController(IStudentService studentService, IMapper mapper)
{
_studentService = studentService;
_studentService.Initialize(new ModelStateWrapper(this.ModelState));
_mapper = mapper;
}
public IActionResult CreateStudent([FromBody] StudentCreationDto student)
{
if (student== null)
{
return BadRequest();
}
if (!ModelState.IsValid)
{
return new UnprocessableEntityObjectResult(ModelState);
}
var studentEnitty = _mapper.Map<Student>(student);
var createSuccessful = _studentService.CreateStudent(studentEnitty);
if (!createSuccessful)
{
return new UnprocessableEntityObjectResult(ModelState);
}
}
Service:
public void Initialize(IValidationDictionary validationDictionary)
{
_validationDictionary = validationDictionary;
}
public bool CreateStudent(Student student)
{
//Check if Student already exists
if (!ValidateStudentToCreate(student))
{
return false;
}
//Create Portal
var createSuccessful = _studentRepository.CreateStudent(student);
if (!createSuccessful)
{
return false;
}
return true;
}
private bool ValidateStudentToCreate(Student student)
{
//throw new Exception();
if (_studentRepository.StudentEmailExists(student.Email))
{
_validationDictionary.AddError("Email", "Student already exists");
}
bool isValid = _validationDictionary.IsValid;
return isValid;
}
I have IValidation dictionary with AddError and IsValid. ModelStateWrapper Implements IValidationDictionary.
IValidation Dictionary
public interface IValidationDictionary
{
void AddError(string key, string errorMessage);
bool IsValid { get; }
}
ModelStateWrapper
public class ModelStateWrapper : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ModelStateWrapper(ModelStateDictionary modelState)
{
_modelState = modelState;
}
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}
public bool IsValid
{
get { return _modelState.IsValid; }
}
I am trying to get the data model validations at Controller level and Business logic such as Student exists at Service level. I am able to execute the validations however, i am unable to get the model state back to Controller as it says valid. Can you please let me know what I am missing?
I have been trying to figure out how to use custom model binding with .net Core 2 web api but have not been able to get it working.
I have been through some articles as below
http://www.palmmedia.de/Blog/2018/5/13/aspnet-core-model-binding-of-abstract-classes
Asp net core rc2. Abstract class model binding
In my case, the bindingContext.ModelName is always empty. Can anybody explain why this could be?
Sample implementation below
Controller
public IActionResult SomeAction([ModelBinder(BinderType = typeof(BlahTypeModelBinder))][FromBody]TheBaseClass theBase)
{
return Ok();
}
Models
public abstract class TheBaseClass
{
public abstract int WhatType { get; }
}
public class A : TheBaseClass
{
public override int WhatType { get { return 1; } }
}
public class B : TheBaseClass
{
public override int WhatType { get { return 2; } }
}
Provider
public class BhalTypeBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (context.Metadata.ModelType == typeof(TheBaseClass))
{
var assembly = typeof(TheBaseClass).Assembly;
var abstractSearchClasses = assembly.GetExportedTypes()
.Where(t => t.BaseType.Equals(typeof(TheBaseClass)))
.Where(t => !t.IsAbstract)
.ToList();
var modelBuilderByType = new Dictionary<Type, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder>();
foreach (var type in abstractSearchClasses)
{
var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>();
var metadata = context.MetadataProvider.GetMetadataForType(type);
foreach (var property in metadata.Properties)
{
propertyBinders.Add(property, context.CreateBinder(property));
}
modelBuilderByType.Add(type, new Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder(propertyBinders));
}
return new BlahTypeModelBinder(modelBuilderByType, context.MetadataProvider);
}
return null;
}
}
Binder
public class BlahTypeModelBinder : IModelBinder
{
private readonly IModelMetadataProvider _metadataProvider;
private readonly IDictionary<Type, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder> _binders;
public BlahTypeModelBinder(IDictionary<Type, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder> binders, IModelMetadataProvider metadataProvider)
{
_metadataProvider = metadataProvider;
_binders = binders;
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
var modelTypeValue = bindingContext.ValueProvider.GetValue(ModelNames.CreatePropertyModelName(bindingContext.ModelName, "WhatType"));
if (modelTypeValue != null && modelTypeValue.FirstValue != null)
{
Type modelType = Type.GetType(modelTypeValue.FirstValue);
if (this._binders.TryGetValue(modelType, out var modelBinder))
{
ModelBindingContext innerModelBindingContext = DefaultModelBindingContext.CreateBindingContext(
bindingContext.ActionContext,
bindingContext.ValueProvider,
this._metadataProvider.GetMetadataForType(modelType),
null,
bindingContext.ModelName);
/*modelBinder*/
this._binders.First().Value.BindModelAsync(innerModelBindingContext);
bindingContext.Result = innerModelBindingContext.Result;
return Task.CompletedTask;
}
}
//More code
}
}
I finally managed to solve the issue. You dont need the provider. Just the following binder works
public class BlahTypeModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
var json = ExtractRequestJson(bindingContext.ActionContext);
var jObject = Newtonsoft.Json.Linq.JObject.Parse(json);
var whatTypeInt = (int)jObject.SelectToken("WhatType");
if (whatTypeInt == 1)
{
var obj = DeserializeObject<A>(json);
bindingContext.Result = ModelBindingResult.Success(obj);
}
else if (whatTypeInt == 2)
{
var obj = DeserializeObject<B>(json);
bindingContext.Result = ModelBindingResult.Success(obj);
}
else
{
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
return Task.CompletedTask;
}
private static string ExtractRequestJson(ActionContext actionContext)
{
var content = actionContext.HttpContext.Request.Body;
return new StreamReader(content).ReadToEnd();
}
private static T DeserializeObject<T>(string json)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(json, new Newtonsoft.Json.JsonSerializerSettings
{
TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto
});
}
}
The examples you linked to use an external query string parameter to determine the type.
If you call your action like this: SomeAction?WhatType=YourNamespaceName.A the binding works as expected.
bindingContext.ModelName being empty is just fine, it would be set after model binding. You can set it after setting bindingContext.Result if you want. Parameter WhatType comes from the QueryStringValueProvider, so no prefix is fine.
How to accomplish abstract model binding based on the JSON alone
To do this, we need:
A value provider to read the JSON and provide us with some "WhatType" value, in place of the QueryStringValueProvider.
Some reflection to map the extracted numbers to the Type-s.
1. ValueProvider
There is a detailed article on creating ValueProviders here:
As a starting point here is some code that successfully extracts the WhatType integers from the body json:
public class BlahValueProvider : IValueProvider
{
private readonly string _requestBody;
public BlahValueProvider(string requestBody)
{
_requestBody = requestBody;
}
private const string PROPERTY_NAME = "WhatType";
public bool ContainsPrefix(string prefix)
{
return prefix == PROPERTY_NAME;
}
public ValueProviderResult GetValue(string key)
{
if (key != PROPERTY_NAME)
return ValueProviderResult.None;
// parse json
try
{
var json = JObject.Parse(_requestBody);
return new ValueProviderResult(json.Value<int>("WhatType").ToString());
}
catch (Exception e)
{
// TODO: error handling
throw;
}
}
}
public class BlahValueProviderFactory : IValueProviderFactory
{
public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var request = context.ActionContext.HttpContext.Request;
if (request.ContentType == "application/json")
{
return AddValueProviderAsync(context);
}
return Task.CompletedTask;
}
private Task AddValueProviderAsync(ValueProviderFactoryContext context)
{
using (StreamReader sr = new StreamReader(context.ActionContext.HttpContext.Request.Body))
{
string bodyString = sr.ReadToEnd();
context.ValueProviders.Add(new BlahValueProvider(bodyString));
}
return Task.CompletedTask;
}
}
Of course you have to register this factory in Startup.cs just as you registered the model binder. And this absolutely misses converting the extracted number to the actual Type (for this, see point 2 below), but if you place a breakpoint on your line staring with if (modelTypeValue != null you can see that modelTypeValue is there for you now even without the separate GET parameter.
2. Reflection
Realize that you are trying to figure out the type based on a property that is dynamically calculated on an existing instance (they are not static). While by knowing the current implementation I know that this is possible (create an empty instance of the model, check the WhatType property, throw the instance away), this is very bad practice, as nothing guarantees that an instance property is statically constant.
The clean solution for this would be an Attribute, that contains the WhatType number for that class. Then we can reflect on that attribute and build a map that maps ints to Types. This is out of the scope if this question, but look up any custom attribute tutorial if you are not familiar, and you will be able to put it together really quickly.
This is my code:
// Controller
[HttpGet("{id}")]
[MyFilter]
public async Task<MyCustomType> Load(string id)
{
return new MyCustomType(....);
}
// Custom attribute
public class MyFilterAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
// Can I have my MyCustomType result here?
}
}
I need to implement some special logic in case of specific property values of MyCustomType result.
Public class MyCustomType
{
// assuming that there will be more properties
public int Id { get; set; }
public string Name { get; set; }
}
// Now, Move to Controller method.
public class CustomController : Controller
{
[HttpGet({"id"})]
[MyFilter]
public async Task<MyCustomType> Load(string id)
{
// Do some async operations
// Or do some Db queries
// returning MyCustomType
MyCustomType typeToReturn = new MyCustomType();
typeToReturn.Id = 1;
typeToReturn.Name = "something";
return typeToReturn;
}
}
// Well here goes the attribute
public class MyFilterAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
// you have to do more digging i am using dynamic to get the values and result.
dynamic content = context.Result;
if (content != null)
{
dynamic values = content.Value;
}
}
}
EDIT changed the code and ran it in a dot net core project and i was able to get the values, how ever i have used dynamic you can dig more on it.
I was just working on some application architecture and this may sound like a stupid question but please explain to me how the following works:
Interface:
public interface IMatterDAL
{
IEnumerable<Matter> GetMattersByCode(string input);
IEnumerable<Matter> GetMattersBySearch(string input);
}
Class:
public class MatterDAL : IMatterDAL
{
private readonly Database _db;
public MatterDAL(Database db)
{
_db = db;
LoadAll(); //Private Method
}
public virtual IEnumerable<Matter> GetMattersBySearch(string input)
{
//CODE
return result;
}
public virtual IEnumerable<Matter> GetMattersByCode(string input)
{
//CODE
return results;
}
Controller:
public class MatterController : ApiController
{
private readonly IMatterDAL _publishedData;
public MatterController(IMatterDAL publishedData)
{
_publishedData = publishedData;
}
[ValidateInput(false)]
public JsonResult SearchByCode(string id)
{
var searchText = id; //better name for this
var results = _publishedData.GetMattersBySearch(searchText).Select(
matter =>
new
{
MatterCode = matter.Code,
MatterName = matter.Name,
matter.ClientCode,
matter.ClientName
});
return Json(results);
}
This works, when I call my controller method from jquery and step into it, the call to the _publishedData method, goes into the class MatterDAL.
I want to know how does my controller know to go to the MatterDAL implementation of the Interface IMatterDAL. What if I have another class called MatterDAL2 which is based on the interface. How will my controller know then to call the right method?
I am sorry if this is a stupid question, this is baffling me.
EDIT:
Based on the responses, it seems like this is where the dependency is being resolved:
This is a ninject call:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICpdMatterDAL>().To<CachedCpdData>();
}
Where CachedCpdData is:
public class CachedCpdData : ICpdMatterDAL
{
private static readonly object CacheLockObject = new object();
private readonly MatterDAL _matterData;
public CachedCpdData()
{
_matterData = DomainModel.DataAccessManager.Instance.Matters;
}
public IEnumerable<Matter> GetMattersForAutoCompleteByCode(string input)
{
var cacheKey = string.Format("matter-search-{0}", input ?? "");
var result = HttpRuntime.Cache[cacheKey] as IEnumerable<Matter>;
if (result == null)
{
lock (CacheLockObject)
{
result = HttpRuntime.Cache[cacheKey] as IEnumerable<Matter>;
if (result == null)
{
result = _matterData.GetMattersForAutoCompleteByCode(input).ToList();
HttpRuntime.Cache.Insert(cacheKey, result, null, DateTime.Now.AddSeconds(60), TimeSpan.Zero);
}
}
}
return result;
}
public IEnumerable<Matter> GetMattersByMatterCodeSearch(string input)
{
return _matterData.GetMattersByMatterCodeSearch(input);
}
}
The rason why your code is using the right implementation of IMatterDAL is because it's being passed as a parameter in the constructor of MatterController. I'm almost sure that your code is using some Dependency Injection framework to resolve IMatterDAL.
In fact Ninject is a DI Framework. Your code should have something like
kernel.Bind<IMatterDAL>().To<MatterDAL >();