How to restrict a webapi controller method invokation using a filter - asp.net-web-api

I have several controllers, and each of them has operations that represents
REST endpoints.
i want to invoke those operations based on conditions
can it be possible to achieve it using filters with attributes and not using (if..else) statements in all operations?
if so, can you please provide a skeleton of how doing it?
thanks.

If it is asp.net core then check please this link https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2
You can do something like this
public class SampleAsyncActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
if (...)
{
// do something before the action executes
var resultContext = await next();
// do something after the action executes; resultContext.Result will be set
}
}
}

Related

Handle data after http get request in angular

I have a service that requests data from a get method, I'd like to map the response to an object storing some Ids and use those Ids to make other http requests.
I was told this isn't usually done in a callback manner, I looked at this How do I return the response from an asynchronous call? but I don't think it's the usual way to implement services, any hints are very appreciated.
Tried adding in onInit/constructor method in angular to be sure the object was filled before other methods were called without success.
#Injectable ()
export class ContactService {
storeIds;
getIds(callback: Function) {
this.http.get<any>(IdsUrl, Config.options).subscribe(res => {
callback(response);
});
getIds(res => {
this.storeIds = {
profileId: res.profile,
refIds: res.refIds
}
}
)
// this.storeIds returns undefined as it's an async call
this.http.post<any>(WebserviceUrl + this.storeIds.profileId , data, headers )
// .....Many other web services that relay on this Ids
}
Just create another service called StoreIdsService. Update the response you get from your first api call 'getIds' in the StoreIdsService. The idea is to have StoreIdsService as singleton service to keep state of your storeIds. You can inject StoreIdsService in anywhere component you want to get the storeIds.
Its one of manyways to share data in angular between components.
Please refer to this answer someone has posted.
How do I share data between components in Angular 2?
You can simply assign the service response to the storeIds property inside the subscribe method. and call the subsequent services inside it if you need.
#Injectable ()
export class ContactService {
storeIds;
getIds() {
this.http.get<any>(IdsUrl, Config.options).subscribe(res => {
this.storeIds = {
profileId: response.profile,
refIds: response.refIds
}
this.otherapicall1();
this.otherapicall2();
});
}

test if call to IAsyncAuthorizationFilter.OnAuthorizationAsync has failed

This question relates to a larger objective outlined in this so question. To recap
I would like to display components of a navigation tree only if a principal has access to those components (whether roles or policy based).
In the previous question I will have a List of the autorization filters which belong to a controller and action. Once I have an instance of the IHttpContextAccessor and therefore the ClaimsPrincipal, how might I test if the principal would pass all the above mentioned list of authorization filters?
That is, if I mocked up something like:
var mockAuthFilter = new AuthorizationFilterContext(...);
foreach (IAsyncAuthorizationFilter filter in filterListForGivenAction)
{
await filter.OnAuthorizationAsync(mockAuthFilter);
The question is - how might I test if any calls to OnAuthorizationAsync have failed?
Alternatively, would there be a better approach altogether to ensure the navigation tree only displays nodes/leaves for which the principal is authorized to view based on the AuthorizeAttribute (policy and/or roles).
It was written there if I had looked closely enough at the annotations on the properties of AuthorizationFilterContext -
[Result] - Setting Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result to a non-null value inside an authorization filter will short-circuit the remainder of the filter pipeline.
Therefore The method ends up being:
private async Task<bool> IsValid(IEnumerable<IAsyncAuthorizationFilter> filters, ActionContext actionContext)
{
var context = new AuthorizationFilterContext(actionContext, filters.Cast<IFilterMetadata>().ToList());
foreach (var f in filters)
{
await f.OnAuthorizationAsync(context);
if (context.Result != null)
{
return false;
}
}
return true;
}

Viewcomponent alternative for ajax refresh

I have a viewcomponent that contains some reusable business logic that embed in various pages. This has been working fine. However, I now have a requirement to refresh the viewcomponent using ajax.
Is there any way to accomplish this? From what I have read, it is not possible, although that info was a bit outdated.
If it is not possible, what is the best alternative?
On beta7 it is now possible to return a ViewComponent directly from a controller. Check the MVC/Razor section of the announcement
The new ViewComponentResult in MVC makes it easy to return the result
of a ViewComponent from an action. This allows you to easily expose
the logic of a ViewComponent as a standalone endpoint.
So you could have a simple view component like this:
[ViewComponent(Name = "MyViewComponent")]
public class MyViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
var time = DateTime.Now.ToString("h:mm:ss");
return Content($"The current time is {time}");
}
}
Create a method in a controller like:
public IActionResult MyViewComponent()
{
return ViewComponent("MyViewComponent");
}
And do a better job than my quick and dirty ajax refresh:
var container = $("#myComponentContainer");
var refreshComponent = function () {
$.get("/Home/MyViewComponent", function (data) { container.html(data); });
};
$(function () { window.setInterval(refreshComponent, 1000); });
Of course, prior to beta7 you could create a view as the workaround suggested by #eedam or use the approach described in these answers

GWT RPC - Parallel asynchronous calls

I have a list of promises that needs to be executed in parallel and in an asynchronous manner.Say,i have,
List<Promise<X>> list;
Once all the parallel request completes, i need to make another request say "Y". Here is my GWT code,
GQuery.when(list).done(...).fail(..)
But the above doesn seem to work!.How can i pass a list of promises to GQuery?.Is the above synctax valid?.
If you create a sample GWT project in Eclipse, a simple asynchronous RPC call is created. You can take that as a template to change it the way you need. With the callback of the request is it possible to display your "Y".
// Set up the callback object.
AsyncCallback<List<Promise<X>>> callback = new AsyncCallback<List<Promise<X>>>() {
public void onFailure(Throwable caught) {
// TODO: Do something with errors.
}
public void onSuccess(List<Promise<X>> result) {
// TODO: DO something with the result.
}
};
You should also read the documentations, at least...
http://www.gwtproject.org/doc/latest/tutorial/RPC.html

Restricting auto Help Page contents when using Attribute Routing in Web API 2

I'm currently implementing a Web API using Web API 2's attribute routing (http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2). I am also using the Help Pages module in order to automatically generate documentation from XML comments (http://www.asp.net/web-api/overview/creating-web-apis/creating-api-help-pages).
For this API I am providing support for optional return format extensions, so that every API method has a pair of routes defined on it like so:
[HttpGet]
[Route("Path/Foo")]
[Route("Path/Foo.{ext}")]
public HttpResponseMessage DoFoo()
{
// Some API function.
}
This allows a user to hit any of these and get a result:
www.example.com/api/Controller/Path/Foo
www.example.com/api/Controller/Path/Foo.json
www.example.com/api/Controller/Path/Foo.xml
My issue is that when Help Pages uses MapHttpAttributeRoutes() to generate documentation, it is picking up both routes for each method. So right now I see help for:
api/Controller/Foo
api/Controller/Foo.{ext}
But I want to only see:
api/Controller/Foo.{ext}
I would prefer to hide the non-extension route on each method, so that every method only shows a single Help Page entry.
Has anyone else tried something similar? Is there a work around that I am missing?
My question would be is that, would consumers of your api figure out easily that the {ext} is optional?...personally, I would prefer the default behavior...but anyways following are some workarounds that I can think of:
A quick and dirty workaround. Split the DoFoo into 2 actions like DoFoo() and DoFooWithExt maybe. Notice that I am using an attribute called ApiExplorerSettings, which is for HelpPage purposes. Example below:
[HttpGet]
[Route("Path/Foo")]
[ApiExplorerSettings(IgnoreApi=true)]
public HttpResponseMessage DoFoo()
{
return DoFooHelper();
}
[HttpGet]
[Route("Path/Foo.{ext}")]
public HttpResponseMessage DoFooWithExt()
{
return DoFooHelper();
}
private HttpResponseMessage DoFooHelper()
{
//do something
}
Create a custom ApiExplorer (which HelpPage feature uses internally) and check for specific routes like the following and can decide whether to show the action or not for that particular route.
// update the config with this custom implementation
config.Services.Replace(typeof(IApiExplorer), new CustomApiExplorer(config));
public class CustomApiExplorer : ApiExplorer
{
public CustomApiExplorer(HttpConfiguration config) : base(config)
{
}
public override bool ShouldExploreAction(string actionVariableValue, HttpActionDescriptor actionDescriptor, IHttpRoute route)
{
if (route.RouteTemplate.EndsWith("Path/Foo", StringComparison.OrdinalIgnoreCase))
{
return false;
}
return base.ShouldExploreAction(actionVariableValue, actionDescriptor, route);
}
}
Get list of all ApiDescription from the default ApiExplorer and then filter out the descriptions which you do not like. Example:
Configuration.Services.GetApiExplorer().ApiDescriptions.Where((apiDesc) => !apiDesc.RelativePath.EndsWith("Path/Foo", StringComparison.OrdinalIgnoreCase))

Resources