Unable to create swagger.json with custom base controller - swagger

I have a controller say 'SampleController' that uses 'MyControllerBase'(from a NuGet package) as a base class.
I am trying to add API documentation using swagger but the swagger is unable to fetch 'SampleController' thus cannot create swagger.json.
I am getting the error "fetch error: /swagger/v1/swagger.json"
'MyControllerBase' inherits 'ControllerBase' so 'SampleController' is working as an API should work.
How can I tell swagger to use 'MyControllerBase' to find Controllers
From Nuget Package:
namespace My.ApiFormatter.Controller
{
public abstract class MyControllerBase<T> : ControllerBase, IFilterableController
{
public virtual Dictionary<string, IFilterMapper> FilterWhitelist => new Dictionary<string, IFilterMapper>();
}
}
Implementation:
[Route("api/[controller]")]
[ApiController]
public class SampleController : MyControllerBase<ExampleData>
{
[HttpGet]
public override ActionResult<CollectionEnvelope<ExampleData>> GetAll()
{
var results = ExampleDatas
.Where(x => x.Key > (Info.PageSize * Info.SkipPages)
&& x.Key <= (Info.PageSize * (Info.SkipPages + 1)))
.Select(y => y.Value).ToList();
var collectionEnvelope = GetCollectionEnvelope(results, ExampleDatas.Count);
return Ok(collectionEnvelope);
}
}

Swagger will just get the methods as controllers in the base class. You are probably getting the error, because swagger thinks any public method is an endpoint. Make the methods and properties that aren't endpoints protected

Related

How to invalidate Web API cache from another Controller(ASP.NET Web API CacheOutput Library)

I have used ASP.NET Web API CacheOutput Library for my asp.net project for web API and it working fine, but have another controller from where I have a POST method and I would like to invalidate my cache from that controller.
[AutoInvalidateCacheOutput]
public class EmployeeApiController : ApiController
{
[CacheOutput(ClientTimeSpan = 100, ServerTimeSpan = 100)]
public IEnumerable<DropDown> GetData()
{
//Code here
}
}
public class EmployeesController : BaseController
{
[HttpPost]
public ActionResult CreateEmployee (EmployeeEntity empInfo)
{
//Code Here
}
}
I would like to invalidate Employees Cache when there is add\update in employee controller.
It is little tricky, but you can get it in this way:
1. On your WebApiConfig:
// Registering the IApiOutputCache.
var cacheConfig = config.CacheOutputConfiguration();
cacheConfig.RegisterCacheOutputProvider(() => new MemoryCacheDefault());
We will need of it to get the IApiOutputCache from GlobalConfiguration.Configuration.Properties, if we let the default properties' setup happen the property with the IApiOutputCache won't exists on MVC BaseController request.
2. Create a WebApiCacheHelper class:
using System;
using System.Linq.Expressions;
using System.Web.Http;
using WebApi.OutputCache.Core.Cache;
using WebApi.OutputCache.V2;
namespace MideaCarrier.Bss.WebApi.Controllers
{
public static class WebApiCacheHelper
{
public static void InvalidateCache<T, U>(Expression<Func<T, U>> expression)
{
var config = GlobalConfiguration.Configuration;
// Gets the cache key.
var outputConfig = config.CacheOutputConfiguration();
var cacheKey = outputConfig.MakeBaseCachekey(expression);
// Remove from cache.
var cache = (config.Properties[typeof(IApiOutputCache)] as Func<IApiOutputCache>)();
cache.RemoveStartsWith(cacheKey);
}
}
}
3. Then, call it from your EmployeesController.CreateEmployee action:
public class EmployeesController : BaseController
{
[HttpPost]
public ActionResult CreateEmployee (EmployeeEntity empInfo)
{
// your action code Here.
WebApiCacheHelper.InvalidateCache((EmployeeApiController t) => t.GetData());
}
}

Injecting dependencies into custom Web API action filter attribute with Autofac

I'm trying to resolve the dependencies of my custom AuthorizeAttribute which I use to decorate my API controllers in an MVC4 app. Problem is that I keep getting a NullReferenceException on the service dependency I use within my custom filter. Here is my Autofac configuration:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerApiRequest();
builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(UserProfileRepository).Assembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(IUserProfileMapper).Assembly)
.Where(t => t.Name.EndsWith("Mapper"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(UserProfileSvc).Assembly)
.Where(t => t.Name.EndsWith("Svc"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterWebApiFilterProvider(config);
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = resolver;
}
}
and my custom authorize filter:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc _authenticationSvc;
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!base.IsAuthorized(actionContext))
{
return false;
}
var trueUserId = WebSecurity.CurrentUserId;
if (_authenticationSvc.GetUsersRoles(trueUserId).Any(x => x == "Admin")) return true;
// NullReferenceException on _authenticationSvc
}
}
According to the official docs all that is needed is:
var builder = new ContainerBuilder();
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
But that doesn't seem to do the trick either. Appreciate any help.
I think Autofac's documentation offers much simpler solution for WebApi action filters.
public interface ServiceCallActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// Get the request lifetime scope so you can resolve services.
var requestScope = actionContext.Request.GetDependencyScope();
// Resolve the service you want to use.
var service = requestScope.GetService(typeof(IMyService)) as IMyService;
// Do the rest of the work in the filter.
service.DoWork();
}
}
It is not "pure DI" as it is using service locator, but it is simple and works with the request scope. You don't need to worry about registering specific action filter for each WebApi controller.
Source:
http://autofac.readthedocs.io/en/latest/integration/webapi.html#provide-filters-via-dependency-injection
You should configure property injection for your attribute
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc AuthenticationSvc { get; set; }
}
and the builder
builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired();
In addition to #Toan Nguyen's answer, if you have this...
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc AuthenticationSvc { get; set; }
}
... it seems you also need (or may need) the first line below:
builder.RegisterFilterProvider();
builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired();
Reference: http://itprojectpool.blogspot.com.au/2014/03/autofac-di-on-action-filters.html
In addition to configuring property injection, as outlined in other answers, you can also explicitly resolve dependencies in the OnActivating callback.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
private IAuthenticationSvc _authenticationSvc;
public void SetAuthenticationSvc(IAuthenticationSvc svc)
{
this._authenticationSvc = svc;
}
}
And then register the type:
builder.RegisterType<MyAuthorizeAttribute>()
.OnActivating(_ => _.Instance.SetAuthenticationSvc(_.Context.Resolve<IAuthenticationSvc>()));
Note: You can do the same with a property instead of a method. I chose to use a method here only to illustrate that this solution was not dependent on PropertiesAutowired.

Injecting a value from MVC controllers

Our repositories and services are currently being injected into our controllers via a Unity container (using the Web API MVC bootstrapper).
public class AnnouncementsController : BaseApiController
{
protected IAnnouncementRepository AnnouncementRepository{ get; set; }
public AnnouncementsController (IAnnouncementRepository announcementRepository)
: base()
{
this.AnnouncementRepository = announcementRepository;
}
public HttpResponseMessage Post([FromBody]GetAnnouncementsModel model)
{
var announcements = AnnouncementRepository.GetByType(model.AnnouncementType);
// ...
}
}
A new requirement has arisen: All input models (e.g. GetAnnouncementsModel) now need to have an AccessToken.
Why? So that results from repositories are filtered according to data rights. Clients are restriction on what data they can consume.
Bad Solution - Pass in token as a method parameter
One solution is to include an AccessToken parameter to every repository or service call. This is not a good solution. We have to implement this in hundreds of methods. An example of this parameter:
public HttpResponseMessage Post([FromBody]GetAnnouncementsModel model)
{
var announcements = AnnouncementRepository.GetByType(model.AccessToken, model.AnnouncementType);
// ...
}
Better Solution - Inject token during resolution
A better solution would be to provide the AccessToken in the repository constructors and have some base implementation that does the filtering logic implicitly.
But how could I do this with dependency injection? The constructor is resolved and called by the Unity container. How could I inject the property value of an input model into this process?
container.RegisterType<IAnnouncementRepository, AnnouncementRepository>(
new InjectionConstructor(
new InjectionParameter<Guid>(AccessToken)
)
);
You can define a custom interface, call it for example IAccessTokenProvider:
interface IAccessTokenProvider
{
Guid Token { get; }
}
Now you can make an implementation like this:
public class HttpContextAccessTokenProvider
{
public Guid Token
{
get { return (Guid)HttpContext.Current.Items["AccessToken"]; }
}
public static void SetToken(Guid token)
{
HttpContext.Current.Items["AccessToken"] = token;
}
}
Now you should be able to implement a filter to read the token from the request:
public class TokenFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string tokenString = filterContext.HttpContext.Request.QueryString["token"];
ActionExecutingContext.SetToken(Guid.Parse(tokenString));
}
}
You can also read the token from other sources or store it in other containers (sessions, cookies, whatever). You can also directly access it in your controller or repositories.
You have 2 options to use the token in your repository:
Inject IAccessTokenProvider to your repository and get the token directly from the provider.
Inject IAccessTokenProvider to your controller and pass the token

MVC 5 Web Api - Inheriting route from base controller

Is it "legal" to have a controller inherit a route from its BaseController ? It seems it's not allowed for Attribute Routing , but how about normal route registration via RouteCollection?
The reason is I currently have a bunch of controllers, each representing some kind of file converter. Each of them has a common set of methods to upload the file to be converted. These method are endpoints on each controller not just private methods. I'd like for the following routes to be valid:
/api/controller1/uploadfile
/api/controller2/uploadfile
/api/controller3/uploadfile
Can I get an example how this could be done inside a BaseController and if it's not possible, an alternative.
Here's what works:
public abstract class BaseUploaderController : ApiController
{
[HttpGet, Route("uploadfile")] //Needs both because HttpGet("uploadfile") currently only supported in MVC attribute routing
public string UploadFile()
{
return "UploadFile";
}
}
[RoutePrefix("api/values")]
public class ValuesController : BaseUploaderController
{
[Route("{id:int}")]
public string Get(int id)
{
return "value";
}
}
Are you looking to place this UploadFile action in the base controller and other controllers inheriting from them should still be able to hit UploadFile from their respective routes like you mentioned in your post? If yes, you could create an abstract base api controller and place this UploadFile action in it and your requests to the individual controllers should work as expected.
Example:
public abstract class BaseApiController : ApiController
{
// POST /api/Values
// POST /api/Test
public string UploadFile()
{
return "UploadFile";
}
}
public class TestController : BaseApiController
{
// GET /api/test/10
public string GetSingle(int id)
{
return "Test.GetSingle";
}
}
public class ValuesController : BaseApiController
{
// GET /api/values/10
public string GetSingle(int id)
{
return "Values.GetSingle";
}
}
As per this answer https://stackoverflow.com/a/21610390/122507 attribute routes are not inherited.
I am currently debating between introducing unnecessary method in 30 controllers just so I can add an attribute route or add a fake parameter to the base class method to let the default routing disambiguate between Get(int id) and GetHistory(int id, bool history) where I don't need the second parameter.

Injecting a specific instance of an interface using Autofac

I am using ASP.NET MVC 3 and Autofac for my dependency injection. I am using AutoMapper for my mapping.
I have an IMapper class that I use for all my model view mappings. So any any of my mapping classes can implement this interface. In the controller below the constructor receives an IMapper instance, and in my User controller it might receive a different instance, maybe userMapper. Getting back to the code below, I have a class called NewsMapper and it implements IMapper. How do I setup dependency injection so that this controller must receive an instance of NewsMapper? Please bear in mind that I might have another mapper called UserMapper.
I have the following controller:
public class NewsController
{
private INewsService newsService;
private IMapper newsMapper;
public NewsController(INewsService newsService, IMapper newsMapper)
{
if (newsService == null)
{
throw new ArgumentNullException("newsService");
}
if (newsMapper == null)
{
throw new ArgumentNullException("newsMapper");
}
this.newsService = newsService;
this.newsMapper = newsMapper;
}
}
I have the following configuration in my global.asax.cs:
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<NewsService>().As<INewsService>();
builder.RegisterType<NewsRepository>().As<INewsRepository>();
UPDATED:
My IMapper interface:
public interface IMapper
{
object Map(object source, Type sourceType, Type destinationType);
}
My NewsMapper class:
public class NewsMapper : IMapper
{
static NewsMapper()
{
Mapper.CreateMap<News, NewsViewModel>();
Mapper.CreateMap<NewsViewModel, News>();
}
public object Map(object source, Type sourceType, Type destinationType)
{
return Mapper.Map(source, sourceType, destinationType);
}
}
My controller action method where I do the mappings:
[HttpPost]
public ActionResult Create(NewsViewModel newsViewModel)
{
// Check model state
if (!ModelState.IsValid)
{
return View("Create", newsViewModel);
}
// Do mapping
var news = (News)newsMapper.Map(newsViewModel, typeof(NewsViewModel), typeof(News));
// Add to database via news service
// Redirect to list view
return RedirectToAction("List", "News");
}
The problem here is the broadness of the IMapper contract. It is too general - the NewsController wants to map something like News to NewsViewModel but IMapper just says "maps something to something."
Instead, have a look at creating a generic variant such as IMapper<TFrom,TTo>. Then, you can set up container so that the NewsController receives an IMapper<News,NewsModel> which is unambiguous and should uniquely match the NewsMapper component (however you decide to set that up.)
Edit
For examples/variants on the generic mapper theme see:
http://consultingblogs.emc.com/owainwragg/archive/2010/12/15/automapper-profiles.aspx
http://lucisferre.net/2009/12/31/graphite-update-the-automapfilter-for-model-e280933e-viewmodel-mapping/
Specifying a default Unity type mapping for a generic interface and class pair

Resources