CacheOutput Attribute Ignoring Azure-hosted Redis Cache - caching

I have just implemented output caching of my Asp.Net Web API Controllers using StrathWeb's library connecting to the StackExchange.Redis library connecting through to an Azure-hosted Redis Cache.
I have written a custom class that implements the StrathWeb IApiOutputCache interface and calls the equivalent StackExchange methods. This is registered as the cache output provder in Global.asax.cs.
Here's an example of usage:
public class MyApiController : ApiController
{
private const int FIFTEEN_MINUTES_IN_SECONDS = 900;
[CacheOutput(ClientTimeSpan = FIFTEEN_MINUTES_IN_SECONDS, ServerTimeSpan = FIFTEEN_MINUTES_IN_SECONDS)]
async public Task<Data> GetAsync(int param1, string param2)
{
return await GetExpensiveData();
}
[Serializable]
public class Data
{
// Members omitted for brevity
}
}
When a call is made to the api endpoint I can see that the framework correctly calls all the required methods on my IApiOutputCache class: Contains, Set and Get. However, even when a cached copy is found and returned, the GetExpensiveData() method is always run and the 'fresh' data returned.
No errors are thrown. The cache seems to be working. Yet, my expensive code is always called.
Thanks for your help :).

Problem solved. I was incorrectly calling into Redis from my IApiOutputCache class.
Before...
public class AzureRedisApiOutputCache : IApiOutputCache
{
public object Get(string key)
{
return AzureRedisCache.Instance.GetDatabase().StringGet(key);
}
}
After...
public class AzureRedisApiOutputCache : IApiOutputCache
{
public object Get(string key)
{
// Call the extension method that also performs deserialization...
return AzureRedisCache.Instance.GetDatabase().Get(key);
}
}
public static class RedisDatabaseExtensions
{
public static object Get(this IDatabase cache, string key)
{
return Deserialize<object>(cache.StringGet(key));
}
}
This confused me for some time as the CacheOutput framework never reported an error. It just silently failed and fell back to the controller method.

Related

Call two Action Methods and Combine the responses to produce new response in .NET Web API

I have two versions of an API.
The second version of API will be having only one action method instead of two action methods in first version of API.
Second version of API action method will basically combine responses of first version of API's both action methods and return combined response to client.
Example code as follows:
[ApiController]
[Route("[controller]")]
public class NumbersV1Controller : ControllerBase
{
private readonly ILogger<NumbersV1Controller> _logger;
public NumbersV1Controller(ILogger<NumbersV1Controller> logger)
{
_logger = logger;
}
[HttpGet]
public int Get()
{
return 1;
}
[HttpPost]
public int Post()
{
return 2;
}
}
[ApiController]
[Route("[controller]")]
public class NumbersV2Controller : ControllerBase
{
private readonly ILogger<NumbersV2Controller> _logger;
public NumbersV2Controller(ILogger<NumbersV2Controller> logger)
{
_logger = logger;
}
[HttpPost]
public IEnumerable<int> Get()
{
// Method 1: Make a direct HTTP request.
// int response1 = HTTPClientHelper.GetRequest("Get", "NumbersV1");
// int response2 = HTTPClientHelper.PostRequest("Post", "NumbersV1");
// Method 2: Use instances and set controller context.
NumbersV1Controller numbersV1Controller = new NumbersV1Controller(null);
numbersV1Controller.ControllerContext = this.ControllerContext;
int response1 = numbersV1Controller.Get();
int response2 = numbersV1Controller.Post();
// Method 3: Use RedirectToAction method.
// RedirectToActionResult response1 = RedirectToAction("Get", "NumbersV1");
// RedirectToActionResult response2 = RedirectToAction("Post", "NumbersV1");
return new List<int>() { response1, response2 };
}
}
Method 1: Make a direct HTTP request.
It works perfectly but it is having additional boilerplate code and also it like making a new network call.
Method 2: Use instances and set controller context.
Not sure if this will work perfectly like can I access the Request object in version 1 controller and not sure how to initialize the version 2 controller will multiple injected objects
Method 3: Use RedirectToAction method.
I was assuming RedirectToAction will work but I don't see the result of the Action method in response object RedirectToActionResult.
What are the best options available for doing this in .NET Web API or is there any other way of doing this elegently?
Avoid using method 2 / method 3. Why? It violates so many patterns and performance will be an issue.
Method 1 is average if you really want to do it that way but will cost a network call though.
Method 4:
You can call directly inline business logic code from your V2 controller. If you already separated your business logic code to an individual service then you need to call it from your controller.
I have introduced a new class to do all the logical operations. You might have a similar one / many service classes for handling business requirements.
Let me give you an example:
public class Number1Controller : BaseController {
// You can use DI container to resolve this. I am using this as an example.
private readonly Service _service = new();
[HttpGet("{id}")]
public int GetById(int id) => _service.GetById(id);
[HttpGet("{name}")]
public string GetByName(string name) => _service.GetByName(name);
}
public class Number2Controller : BaseController {
// You can use DI container to resolve this. I am using this as an example.
private readonly Service _service = new();
[HttpGet("{id}")]
public int GetById(int id) => _service.GetById(id);
[HttpGet("{name}")]
public string GetByName(string name) => _service.GetByName(name);
}
// Business Logic Service
public class Service {
public int GetById(int id) => 1;
public string GetByName(string name) => "Stack Over Flow";
}

How to access Identity UserManager in Web API Controller to Send an Email

I am using Identity v2 and need to send an Email from Web Api Controller using the UserManager.SendAsync method which is OWIN Middleware component. But I don't know how do I access the UserManager itself in Web Api Controller Method. I am trying a similar approach like a Regular MVC controller but usermanager always null. Any suggestion please?
public class MyApiController: ApiController
{
public MyApiController()
{
}
public MyApiController(ApplicationUserManager userManager)
{
UserManager = userManager;
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
public void SendEmail()
{
_userManager.SendAsync(...);
}
}
The constuctor that takes a ApplicationUserManager will never be called with your current solution. Change your empty constructor to call your other constructor.
public class MyApiController: ApiController
{
public MyApiController()
: this(new ApplicationUserManager())
{
}
THE REST OF YOUR IMPLEMENTATION GOES HERE
}
Check whether you have correctly configured UserManager from Startup class
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.DataProtection;
using Owin;
namespace Identity_PasswordPolicy
{
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
///...
// Configure the UserManager
app.UseUserManagerFactory(new IdentityFactoryOptions<ApplicationUserManager>()
{
DataProtectionProvider = app.GetDataProtectionProvider(),
Provider = new IdentityFactoryProvider<ApplicationUserManager>()
{
OnCreate = ApplicationUserManager.Create
}
});
/// ...
}
}
}
Like here in Startup.Auth class from asp.net identity samples
https://aspnet.codeplex.com/SourceControl/latest#Samples/Identity/Identity-PasswordPolicy/Identity-PasswordPolicy/App_Start/Startup.Auth.cs
Startup is partial class and method ConfigureAuth by link is called from https://aspnet.codeplex.com/SourceControl/latest#Samples/Identity/Identity-PasswordPolicy/Identity-PasswordPolicy/Startup.cs
In sample it is called from owin startup method, but depending from hosing it could be called from global.asax.cs

Attribute routing and inheritance

I am playing around with the idea of having a base controller that uses a generic repository to provide the basic CRUD methods for my API controllers so that I don't have to duplicate the same basic code in each new controller. But am running into problems with the routing attribute being recognized when it's in the base controller. To show exactly what the problem I'm having I've created a really simple WebAPI controller.
When I have a Get method in the main Controller and it inherits from the ApiController directly I don't have any problems and this works as expected.
[RoutePrefix("admin/test")]
public class TestController : ApiController
{
[Route("{id:int:min(1)}")]
public string Get(int id)
{
return "Success";
}
}
When I move the Get method into a base controller it is returning the contents of the 404 page.
[RoutePrefix("admin/test")]
public class TestController : TestBaseController
{
}
public class TestBaseController : ApiController
{
[Route("{id:int:min(1)}")]
public string Get(int id)
{
return "Success";
}
}
Some more interesting notes:
I can access the action at GET /Test/1. So it is finding it based on the default route still.
When I try to access POST /admin/test, it returns the following JSON
{
"Message":"No HTTP resource was found that matches the request URI 'http://test.com/admin/test'.",
"MessageDetail":"No type was found that matches the controller named 'admin'."
}
Does anyone know of a way to get the routing to work with attributes from a base controller?
Attribute routes cannot be inherited. This was a deliberate design decision. We didn't feel right and didn't see valid scenarios where it would make sense to inherit them.
Could you give a more realistic scenario as to where you would want to use this?
[Update(3/24/2014)]
In the upcoming 5.2 release of MVC Web API, there is going to be an extensibility point called System.Web.Http.Routing.IDirectRouteProvider through which you can enable the inheritance scenario that you are looking for here. You could try this yourself using the latest night builds(documentation on how to use night builds is here)
[Update(7/31/2014)]
Example of how this can be done in Web API 2.2 release:
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
//---------
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
// inherit route attributes decorated on base class controller's actions
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
Using Web API 2.2, you can:
public class BaseController : ApiController
{
[Route("{id:int}")]
public string Get(int id)
{
return "Success:" + id;
}
}
[RoutePrefix("api/values")]
public class ValuesController : BaseController
{
}
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
as outlined here: http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-22
Got it.
[Route("api/baseuploader/{action}")]
public abstract class BaseUploaderController : ApiController
{
[HttpGet]
public string UploadFile()
{
return "UploadFile";
}
}
[Route("api/values/{action}")]
public class ValuesController : BaseUploaderController
{
[HttpGet]
public string Get(int id)
{
return "value";
}
}
One caveat here is that the route action paramter must be the same as the action name. I could not find a way to get around that. (You cannot rename the route with a RouteAttribute)

ASP.Net MVC 3 - unitOfWork.Commit() not saving anything

I created a web application using ASP.Net MVC 3 and EF 4.1, and I am using the UnitOfWork pattern, but nothing is getting committed to the database. All this is quite new to me, and I don't know where to start to resolve this issue.
I based myself on this post to create my web application:
http://weblogs.asp.net/shijuvarghese/archive/2011/01/06/developing-web-apps-using-asp-net-mvc-3-razor-and-ef-code-first-part-1.aspx
The final code, which can be obtained here also has a service layer and the UnitOfWOrk is being injected into the services.
Instead of using the custom injector based on Unity 2 as they are in that project, I am using Unity.Mvc3.
Here is my IUnitOfWork class:
public interface IUnitOfWork
{
void Commit();
}
And here is my UnitOfWork class:
public class UnitOfWork : IUnitOfWork
{
private readonly IDatabaseFactory databaseFactory;
private MyProjectContext dataContext;
public UnitOfWork(IDatabaseFactory databaseFactory)
{
this.databaseFactory = databaseFactory;
}
protected MyProjectContext DataContext
{
get { return dataContext ?? (dataContext = databaseFactory.Get()); }
}
public void Commit()
{
DataContext.Commit();
}
}
And here is how one of my service class look like:
public class RegionService : IRegionService
{
private readonly IRegionRepository regionRepository;
private readonly IUnitOfWork unitOfWork;
public RegionService(IRegionRepository regionRepository, IUnitOfWork unitOfWork)
{
this.regionRepository = regionRepository;
this.unitOfWork = unitOfWork;
}
...
}
At start-up, my UnitOfWork component is being registered like this:
container.RegisterType<IUnitOfWork, UnitOfWork>();
Now, no matter whether I try to insert, update or delete, no request is being sent to the database. What am my missing here?
UPDATE:
Here is the content of DataContext.Commit():
public class MyProjectContext : DbContext
{
public DbSet<Region> Regions { get; set; }
public virtual void Commit()
{
base.SaveChanges();
}
}
And here is databaseFactory.Get():
public interface IDatabaseFactory : IDisposable
{
MyProjectContext Get();
}
UPDATE #2:
Using the debugger, I am noticing that my Region service and controller constructors are getting called once when performing only a select, but they are called twice when performing an update. Is this normal?
Ok, I found the culprit. It has to do with how I was registering my database factory.
Instead of
container.RegisterType<IDatabaseFactory, DatabaseFactory>();
I needed
container.RegisterType<IDatabaseFactory, DatabaseFactory>(new HierarchicalLifetimeManager());
I found the information on this web site:
http://www.devtrends.co.uk/blog/introducing-the-unity.mvc3-nuget-package-to-reconcile-mvc3-unity-and-idisposable
That's an awfully complex implementation of Unit of Work. I actually prefer this one:
http://azurecoding.net/blogs/brownie/archive/2010/09/22/irepository-lt-t-gt-and-iunitofwork.aspx
Much simpler, and much more flexible. Although you do have to work out a few things for yourself.
May just be a typo but in UnitOfWork your private MyProjectContext is called dataContext (lowercase d)
But in your commit method your calling DataContext.Commit. Any chance that's actually calling a static method that you didn't intend to call? More likely a typo but thought I'd point it out.
+1 for an overly complex implementation of UnitOfWork.

Issues with my MVC repository pattern and StructureMap

I have a repository pattern i created on top of the ado.net entity framework. When i tried to implement StructureMap to decouple my objects, i kept getting StackOverflowException (infinite loop?). Here is what the pattern looks like:
IEntityRepository where TEntity : class
Defines basic CRUD members
MyEntityRepository : IEntityRepository
Implements CRUD members
IEntityService where TEntity : class
Defines CRUD members which return common types for each member.
MyEntityService : IEntityService
Uses the repository to retrieve data and return a common type as a result (IList, bool and etc)
The problem appears to be with my Service layer. More specifically with the constructors.
public PostService(IValidationDictionary validationDictionary)
: this(validationDictionary, new PostRepository())
{ }
public PostService(IValidationDictionary validationDictionary, IEntityRepository<Post> repository)
{
_validationDictionary = validationDictionary;
_repository = repository;
}
From the controller, i pass an object that implements IValidationDictionary. And i am explicitly calling the second constructor to initialize the repository.
This is what the controller constructors look like (the first one creates an instance of the validation object):
public PostController()
{
_service = new PostService(new ModelStateWrapper(this.ModelState));
}
public PostController(IEntityService<Post> service)
{
_service = service;
}
Everything works if i don't pass my IValidationDictionary object reference, in which case the first controller constructor would be removed and the service object would only have one constructor which accepts the repository interface as the parameter.
I appreciate any help with this :) Thanks.
It looks like the circular reference had to do with the fact that the service layer was dependent on the Controller's ModelState and the Controller dependent on the Service layer.
I had to rewrite my validation layer to get this to work. Here is what i did.
Define generic validator interface like below:
public interface IValidator<TEntity>
{
ValidationState Validate(TEntity entity);
}
We want to be able to return an instance of ValidationState which, obviously, defines the state of validation.
public class ValidationState
{
private readonly ValidationErrorCollection _errors;
public ValidationErrorCollection Errors
{
get
{
return _errors;
}
}
public bool IsValid
{
get
{
return Errors.Count == 0;
}
}
public ValidationState()
{
_errors = new ValidationErrorCollection();
}
}
Notice that we have an strongly typed error collection which we need to define as well. The collection is going to consist of ValidationError objects containing the property name of the entity we're validating and the error message associated with it. This just follows the standard ModelState interface.
public class ValidationErrorCollection : Collection<ValidationError>
{
public void Add(string property, string message)
{
Add(new ValidationError(property, message));
}
}
And here is what the ValidationError looks like:
public class ValidationError
{
private string _property;
private string _message;
public string Property
{
get
{
return _property;
}
private set
{
_property = value;
}
}
public string Message
{
get
{
return _message;
}
private set
{
_message = value;
}
}
public ValidationError(string property, string message)
{
Property = property;
Message = message;
}
}
The rest of this is StructureMap magic. We need to create validation service layer which will locate validation objects and validate our entity. I'd like to define an interface for this, since i want anyone using validation service to be completely unaware of the StructureMap presence. Besides, i think sprinkling ObjectFactory.GetInstance() anywhere besides the bootstrapper logic a bad idea. Keeping it centralized is a good way to insure good maintainability. Anyway, i use the decorator pattern here:
public interface IValidationService
{
ValidationState Validate<TEntity>(TEntity entity);
}
And we finally implement it:
public class ValidationService : IValidationService
{
#region IValidationService Members
public IValidator<TEntity> GetValidatorFor<TEntity>(TEntity entity)
{
return ObjectFactory.GetInstance<IValidator<TEntity>>();
}
public ValidationState Validate<TEntity>(TEntity entity)
{
IValidator<TEntity> validator = GetValidatorFor(entity);
if (validator == null)
{
throw new Exception("Cannot locate validator");
}
return validator.Validate(entity);
}
#endregion
}
I'm going to be using validation service in my controller. We could move it to the service layer and have StructureMap use property injection to inject an instance of controller's ModelState to the service layer, but i don't want the service layer to be coupled with ModelState. What if we decide to use another validation technique? This is why i'd rather put it in the controller. Here is what my controller looks like:
public class PostController : Controller
{
private IEntityService<Post> _service = null;
private IValidationService _validationService = null;
public PostController(IEntityService<Post> service, IValidationService validationService)
{
_service = service;
_validationService = validationService;
}
}
Here i am injecting my service layer and validaton service instances using StructureMap. So, we need to register both in StructureMap registry:
ForRequestedType<IValidationService>()
.TheDefaultIsConcreteType<ValidationService>();
ForRequestedType<IValidator<Post>>()
.TheDefaultIsConcreteType<PostValidator>();
That's it. I don't show how i implement my PostValidator, but it's simply implementing IValidator interface and defining validation logic in the Validate() method. All that's left to do is call your validation service instance to retrieve the validator, call the validate method on your entity and write any errors to ModelState.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "PostId")] Post post)
{
ValidationState vst = _validationService.Validate<Post>(post);
if (!vst.IsValid)
{
foreach (ValidationError error in vst.Errors)
{
this.ModelState.AddModelError(error.Property, error.Message);
}
return View(post);
}
...
}
Hope i helped somebody out with this :)
I used a similar solution involving a generic implementor of IValidationDictionary uses a StringDictionary and then copied the errors from this back into the model state in the controller.
Interface for validationdictionary
public interface IValidationDictionary
{
bool IsValid{get;}
void AddError(string Key, string errorMessage);
StringDictionary errors { get; }
}
Implementation of validation dictionary with no reference to model state or anything else so structuremap can create it easily
public class ValidationDictionary : IValidationDictionary
{
private StringDictionary _errors = new StringDictionary();
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_errors.Add(key, errorMessage);
}
public bool IsValid
{
get { return (_errors.Count == 0); }
}
public StringDictionary errors
{
get { return _errors; }
}
#endregion
}
Code in the controller to copy the errors from the dictionary into the model state. This would probably be best as an extension function of Controller.
protected void copyValidationDictionaryToModelState()
{
// this copies the errors into viewstate
foreach (DictionaryEntry error in _service.validationdictionary.errors)
{
ModelState.AddModelError((string)error.Key, (string)error.Value);
}
}
thus bootstrapping code is like this
public static void BootstrapStructureMap()
{
// Initialize the static ObjectFactory container
ObjectFactory.Initialize(x =>
{
x.For<IContactRepository>().Use<EntityContactManagerRepository>();
x.For<IValidationDictionary>().Use<ValidationDictionary>();
x.For<IContactManagerService>().Use<ContactManagerService>();
});
}
and code to create controllers is like this
public class IocControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return (Controller)ObjectFactory.GetInstance(controllerType);
}
}
Just a quick query on this. It's helped me out quite a lot so thanks for putting the answer up, but I wondered which namespace TEntity exists in? I see Colletion(TEntity) needs System.Collections.ObjectModel. My file compiles without anything further but I see your TEntity reference highlighted in Blue which suggests it has a class type, mine is Black in Visual Studio. Hope you can help. I'm pretty keen to get this working.
Have you found any way to seperate validation into the service layer at all? My gut tells me that validating in the Controller is a bit smelly but I've looked high and low to find a way to pass validation error messages back to the controller without tightly coupling the service layer to the controller and can't find anything. :(
Again, thanks for the great post!
Lloyd

Resources