User-Agent in mvc 5 application - c#

I Have a MVC 5 application whose back-end is web API. For each request to my server I need to provide user-agent which I can get in controller action method like var UserAgent = Request.UserAgent.ToString(); and pass subsequently in other class like (Controller => Service => HttpRequester => XXXHttpClient) and finally use in actual request in XXXHttpClient class but I think there could be a better way to achieve the same. I tried to google it but didn't find anything relevant so can anyone guide me what would be the best practice If I want to get user-agent directly in XXXHttpClient class instead of passing subsequently.

Little bit of a broad question with a lot of possible answers.
Passing the data through all the layers is usually not a good thing.
What I would do is make an MVC action filter that grabs the user agent and sets it to an object. The object class could be like this:
public class RequestContext
{
public string UserAgent { get; set; }
}
Use your dependency injection framework to inject this once-per-request. Then the action filter and the layer that depends on the data would use the same instance, allowing you to get the data to any layer that needs it.
Another option which uses a static property:
HttpContext.Current.Request.UserAgent
Greater performance, easier to read, but lower testability :)

Related

ASP.NET Core - Add Custom Property to HttpRequest

I have some ASP.NET Middleware that analyzes a request as it comes in. Based on what's available in that HttpRequest, I would like to add a custom property that I can use in my code. My question is, is there a way for me to add a property to HttpRequest so that I can access it in my controller? For example, in my Controller, I would like to do something like this:
namespace MyWebsite.Controllers
{
public class MyController : Controller
public IActionResult Index()
{
if (this.Request.MyProperty == null)
{
return View("~/Views/NoExist.cshtml");
}
return View ("/Views/Index.cshtml");
}
}
MyProperty represents the custom property that I would like to inject, or add, via my custom middleware. Is this possible? If so, how? If not, what is the recommended approach?
Thank you!
The traditional way of achieving what you want is sharing everything via HttpContext.Items. That way you should manage the keys yourself or even can declare your extension methods for conveniently setting & getting the values.
However here I'd like to introduce a new way associated with a new concept request feature in asp.net core. The features associated with each request can be added by different middlewares along the pipeline and can be consumed by any (if available). That looks like neater and more organized, although may not be very convenient compared to the old way.
Suppose you're in the context of your middleware, the following code will add a feature which exposes your property:
//declare the feature interface first
public interface IMyFeature {
string MyProperty {get;}
}
//the concrete type for the feature
public class MyFeature : IMyFeature {
public MyFeature(string myProperty){
MyProperty = myProperty;
}
public string MyProperty {get;}
}
//the context is in your middleware
//add the feature
var myFeature = new MyFeature("value of your choice");
//context here is the HttpContext
context.Features.Set<IMyFeature>(myFeature);
Now anywhere later in the pipeline, you can consume the feature added like this:
//context here is the HttpContext
var myFeature = context.Features.Get<IMyFeature>();
if(myFeature != null){
//consume your feature
}
One point I think the request features concept is good about is its clear definition of feature interfaces which can be learned, referenced and managed easily by your code. Even porting it to some library for reusing makes more sense than depending on some constant key for accessing the shared data (as achieved by using HttpContext.Items). Of course for some simple data sharing, you can just use HttpContext.Items, the request feature should be used when it may evolve later, has a clear cool concept around it and may contain more data.
Create a singleton that has a readonly ConcurrentDictionary property. Alternatively, create a static class with a readonly static property of type ConcurrentDictionary.
Add a readonly Queue property to your global class.
Use the HttpContext.TraceIdentifier as a unique key and add
the data to the ConcurrentDictionary as the value. Also add the HttpContext.TraceIdentifier and DateTime.Now to the Queue property.
Create a clean-up method that removes old data from the Queue and ConcurrentDictionary by pulling data off the Queue until it is under a particular age, say 90 seconds.
Create a background worker that runs periodically and calls the cleanup method. There are libraries that do this. You can also spin off a thread at startup, but this lacks redundancy unless you code it.
Access your data from any called code using the key HttpContext.TraceIdentifier.
Happy Coding!

C#: How to Apply Serialization in API Controller Level to Obtain Certain Columns

We currently have Repository Layer and App Service Layer.
Repo gets data from SQL Server database with Entity Framework.
App Service Layer Collects data, and does more things: send emails, parse flat files,
Repo Layer
public Task<Sales> GetBySalesId(int salesId)
{
var salesData = _context.Sales
.Include(c => c.Customer)
.FirstOrDefaultAsync(c => c.SalesId == salesId);
return salesData ;
}
Service Layer:
public async Task<SalesDto> GetSalesByIdAppService(int salesId)
{
var salesData = await _salesRepository.GetBySalesId(salesId);
var salesDto = _mapper.Map<SalesDto>(salesData);
return salesDto;
}
This is currently working fine. However tomorrow, one of my colleagues may require More columns, when they aren't needed in my specific portion of application.
Here two more Linq includes are added: However, I do not need Product or Employee.
New Repo Addition:
public Task<Sales> GetBySalesId(int salesId)
{
var salesData = _context.Sales
.Include(c => c.Customer)
.Include(c => c.ProductType)
.Include(c => c.Employee)
.FirstOrDefaultAsync(c => c.SalesId == salesId);
return salesData ;
}
Background One Suggestion is create Another Middle Domain Layer that everyone can utilize. In the API DTO Level, everyone can have separate DTOs, which only collects the only required class members from Domain. This would essentially entail creating Another layer, where DTO is a subset of the new "Domain" layer.
*Another suggestion, is to apply serialization only for the columns which are required. I keep hearing about this, however, how can this be done? Is it possible to application serialization to the Controller API without adding another layer? Does Newtonsoft have a tool, or any syntax in C# ?
API Controller
public async Task<ActionResult<SalesDto>> GetSalesBySalesId(string salesId)
{
var dto = await _service.GetBySalesId(salesId);
return Ok(dto);
}
JSON Ignore may not work , because we all share same DTO, and ignoring for one area, may be required for other part of application.
Decorate your members in class with [JsonIgnore] attribute which are NOT required in response. JsonIgnore is available in
System.Text.Json.Serialization namespace.
public class SalesDto
{
[JsonIgnore]
public string Customer { get; set; }
public string ProductType { get; set; }
public string Employee { get; set; }
}
Bind all properties of model with data and when you send it to UI, Customer property would not be available in response.
We should fetch all the data from database and the process that data in our presentation layer. GraphQL, could be a winner for this scenario but need to explore
OData as a Middle Domain Layer can be useful to support this type of requirement. It gives the caller some control over the shape of the Object Graph that is returned. The code to acheive this is too involved to include as a single POST, however these types of requirements are often better solved through implementing an architecture that is designed specifically to deal with them, rather than rolling your own quick fix.
You can also look at GraphQL that allows greater flexibility over the shape of the returned data, however that is a steeper learning curve for the server and client side.
The problem with just using JsonIgnore is that this is a permanent definition on your DTO, which would make it hard to use the same DTO definitions for different applications that might require a different shape/view of the data.
A solution to that problem is then to create a tightly-coupled branch of DTOs for each application that inherits from the base but overrides the properties by decorating their properties with JsonIgnore attributes.
You want to avoid tightly coupled scenarios where the UI enforces too much structure on your data model, this can will make it harder to maintain your data model and can lead to many other anti-patterns down the track.
OData allows a single set of DTOs that have a consistent structure in the backend and the client end, whilst allowing the client end to reduce/omit/ignore fields that it either does not know about yet or does not want transmitted.
The key here is that the Client now has (some) control over the graph, rather than the API needing to anticipate or tightly define the specific properties that each application MUST consume.
It has a rich standard convention based query language that means many off the shelf products may be able to integrate directly with your API
Some Pros for consideration:
Single Defintion of DTOs
Write once, defining the full structure of your data model that all applications will have access to.
Clients can specify the fields that they need through query projections.
Expose Business Logic through the API
This is a feature of all APIs / Service layers, however OData has a standard convention for supporting and documenting custom business Functions and Actions
Minimal DTOs over the wire
OData serializer can be configured to only transmit properties that have values across the wire
Callers can specify which fields to include in query results
You can configure the default properties and navigation links to send for resource requests when the client does not specify the projection.
PATCH (delta) Updates
OData has a simple mechanism to support partial updates to objects, you only send the changed properties over the wire for any object
Sure, this is really part of the previous point, but it is a really strong argument for using OData over a standard REST based API
You can easily inject business rules into the query validation pipeline (or the execution) to prevent updates to specific fields, this can include role based or user based security context rules.
.Net LINQ Support
Whilst the API is accessed via URL conventions, these conventions can be easily mapped to .Net LINQ queries on the client side via the ODataLib or Simple OData Client.
Not all possible LINQ functions and queries are supported, but there is enough there to get the job done.
This means you can easily support C# client side applications.
Versioning can be avoided
This becomes a Con as well, however additive changes to the data model can be easily absorbed into the runtime without having to publish a new version of the API.
All of the above points contribute to allow Additive changes to be freely supported by down level clients without interruptions.
It is possible to also map some old fields across to new definitions in cases where you want to rename fields, or you can provide default implementations for fields that have been removed.
The OData Model is a configuration that defines how URL requests are mapped or translated to endpoints on the API controllers, meaning there is a layer where you can change how client requests are mapped to
Key Cons to be aware of:
Performance - OData API uses HTTP protocols, so there is an inherent performance hit when compared to local DLL calls, windows services or RPC, even when the API and Application are located on the same machine
This performance hit can be minimised and is usually an acceptable overall cost
GraphQL and most other REST/HTTP based API architectures will have similar JSON over HTTP performance issues.
OData is still a Good fit for JSON over HTTP based remote API hosting scenarios, like javascript based clients.
Poor support for updating related objects
While PATCH is great for single objects, it doesn't work for nested object graphs, to support updates to nested objects you either need to manually keep a repository of changes on the client side and manually call path on each of the nested objects.
The OData protocol does have a provision for batching multiple queries so they can be executed as an atomic operation, but you still have to construct the individual updates.
There is a .Net based OData Client Generation Tool can be used to generate a client side repo to manage this for you.
How often are you expecting your client to send back a rich collection of objects to update in a single hit?
Is it a good idea to allow the client to do this, does an omitted field from the client mean we should set that property to null, does it mean we should delete that related data?
Consider creating actions on the API to execute operations that affect multiple records to keep your clients thin and to consolidate logic so that each of your client applications does not have to re-implement the complex logic.
Version Support
Versioning can be a long term issue if you want to allow destructive changes to your data model and DTOs. While the standard URL conventions support versioning the code to implement it is still complex
Versioning can be hard to implement in any APIs, however the ability to set default projections for each DTO and with the client able to control their own specific projections means that the OData model is more resilient to additive-only changes, such as adding more tables, or fields.
Additive changes can be implemented without interrupting client applications.
Fixed Schema
Although clients can request specific fields to be sent over the wire for the DTOs, including navigation properties, the client cannot easily request the data to come back in a totally different structure. Clients can only really request that certain fields are omitted from results.
There is support for $apply URL parameter to return the results of aggregate operations, but this doesn't provide full control over the shape of the results.
GraphQL does address this exact issue. Moving the mapping from the API to the client side, giving the client a more control over the schema.
the solution for this problem is very simple , you can use half generic query for this , WITHOUT changing anything in your DTO.
first let your repo function takes a generic include like this:
public Task<Sales> GetBySalesId(string salesId, Func<IQueryable<Sales>, IIncludableQueryable<Sales, object>> include = null)
{
var query = _context.Sales.Where(x => x.Id == salesId);
if (include != null)
query = include(query);
var salesData = query.FirstOrDefaultAsync();
return salesData;
}
this can be used in service layer like this:
public async Task<Sales> GetById(string salesId)
{
var result = await _yourRepo.GetBySalesId(salesId,
include: source => source
.Include(a => a.SOMETHING)
.Include(a => a.SOMETHING)
.ThenInclude(a => a.SOMETHING));
return result;
}
now to specialize the query result you can either do it based on your token (if you are using authorization in your api) or can create a number of service functions , call them based on a condition you recieve in the controller like an integer or something.
public async Task<Sales> test(string salesId)
{
Func<IQueryable<Sales>, IIncludableQueryable<Sales, object>> include = null;
if (UserRole == "YOU")
include = a => a.Include(a => a.SOMETHING);
else if (UserRole == "SomeoneElse")
include = a => a.Include(a => a.SOMETHING).ThenInclude(a=>a.SOMETHINGELSE);
var result = await _yourRepo.GetBySalesId(salesId,
include: include);
return result;
}
First of all
your logic is strange: you request DB return all columns and then take only few needed, it is inefficient. Imagine you have 20 columns...
var salesData = await _salesRepository.GetBySalesId(salesId);
var salesDto = _mapper.Map<SalesDto>(salesData);
Should a sales repository be able to include customers and products?
It is probably a holywar subject. Generally speaking, if your architecture wont allow you to switch from DB to file storage and from ASP.NET MVC to Console App, most likely it has design flaws (and it might be perfectly OK for your company current needs)
Summary
You need to make more service methods that do build results not just transferring data from Repo to caller as is.
For your case you need your service to cover more scenarios
AppService.GetSalesById(salesId)
AppService.GetSalesWithProductsById(sales)
AppService.GetSalesById(salesId, includeProducts, includeCustomers)
My personal preference is to change multiple parameters with Commands and make service methods return Results.
If your colleague were to add say 2 columns - it is easier to add them to existing result, if colleague is writing something new – its better to introduce new Method and result
Commands and results
Command stands for some situation and its variations, service looks nice are clean. This approach is time tested on one of my projects for last 10 years. We have switched database 3 times, several ORMs and 2 UIs. To be specific we use ICommand and IResult to make it super flexible.
API Controller
public async Task<ActionResult<SalesDto>> GetSalesBySalesId(string salesId)
{
UISalesTable dto = await (UISalesTable) _service.GetSales(new GetSalesForUICommand
{
SalesId = salesId,
IncludeProductType = true,
IncludeCustomer = false
});
return Ok(dto);
}
public async Task<ActionResult<MonthlySales>> GetSalesReport(string salesId)
{
MonthlySales dto = await (MonthlySales) _service.GetSales(new GetMonthlySalesReportCommand
{
SalesId = salesId,
// extra filters goes here
});
return Ok(dto);
}
Service layer
You make as many DTOs as there are results (it costs nothing)
public async Task<UISalesTable> GetSales(GetMonthlySalesReportCommand command)
{
UISalesTable result = new UISalesTable();
// good place to use Builder pattern
result.SalesByMonthes = .....;
TopProductsCalculator calc = new TopProductsCalculator();
result.TopProducts = calc.Calculate(command.FromDate, command.ToDate);
result.Etc = .....;
return result;
}
It all depends
Unfortunately, there is no recipe. It is always tradeoff between quality and time-to-market. Last years I preferer to keep things simple and even abandoned idea of repositories and now I work with DataContext directly because if I were to switch say to MongoDB, I would have to write every single repository method again and it happens few times in a life.

Automapper WebApi middleware?

I have a lot of controller methods and most of them have the same duplicating code
[Route("test"), HttpPost]
public ResponceViewModel Test(RequestViewModel model)
{
Model data = model.MapTo<Model>();
ResponceModel responce = service.DoWork(data);
return responce.MapTo<ResponceViewModel>();
}
Is it feasible to create WebApi middleware that does mapping by default. What I mean is that it checks if there is mapping between ResponceViewModel and ResponceModel and if such exists executes it. This way i will not need to write this code in every method? I will probably create some attribute to have control to stop this functionality on certain endpoints if needed. Is this good approach, if not why?

Conflicting routes in ASP.NET Core when using Attribute based routing

Context
I am trying to build an ASP.NET Core web API controller that will expose the following methods with specific semantics:
/api/experimental/cars — get entire collection
[HttpGet("/api/experimental/cars/")]
public Task<List<Car>> AllCars()
/api/experimental/cars/123 — get car by id "123"
[HttpGet("/api/experimental/cars/{carId}")]
public Task<Car> CarById([FromRoute] string carId)
/api/experimental/cars?nameFilter=Maz — get cars that match nameFilter = "Maz"
[HttpGet("/api/experimental/cars/{nameFilter?}")]
public Task<List<Car>> CarsByNameFilter([FromQuery] string nameFilter = "")
/api/experimental/cars?nameFilter=Maz&rating=2 — get cars that match nameFilter = "Maz" and with rating greater or equal to 2
[HttpGet("/api/experimental/cars/{nameFilter?}/{rating?}")]
public Task<List<Car>> CarsByNameAndRatingFilter([FromQuery] string nameFilter = "", [FromQuery] int rating = 1)
Note: I really want to keep the controller class clean and have a single method per Web API route — is it possible?
Problem
As you could guess, there's an issue with these API definitions. Basically, AllCars is intercepting pretty much all the requests. (When I was able to get at least the /api/experimental/cars/{carId} working, the query-string based APIs were still not working and intercepted by another method...
I tried many possible route syntaxes to express what I want with no luck. Is it even possible to use the default routing mechanism or I need to implement my own Router class or Middleware or something else?
Update 1: Problem definition
I know I can join at least three methods and their routes into a single WebAPI method that is being smart about the received parameters. Notice that this is exactly what I am trying to avoid.
Why?
Reason 1: I saw that in non-.NET routers, it worked well and there's no technical impossibility to implement semantic based route resolution.
Reason 2: I perceive all four URL patterns mentioned above as four different routes. One may not agree with me and it's okay, but for my purposes the methods and the routes are different and have to stay different.
Reason 3.1: This keeps controller code clean. Every method only handles one specific case. Parameter names are sufficient to properly resolve the routes (at least in humans head, therefore machine can do it too -- it's easy to formalize the algorithm). If client make a request with an unsupported query parameter, it should result in HTTP 404 Not Found or HTTP 400 Bad Request -- totally fine (client rather construct correct URLs).
Reason 3.2: On contrary, if I join the methods and use a more generic route, my implementation needs to be 'smart' about the combination of parameters. This is effectively, a leak of routing abstractions into a layer where it does not belong in my architecture. Complex validation is another thing I don't want to see in the Controller -- less code is better.
Update 2: Nancy — Another .NET example (other that .NET Core WebApi)
There is Nancy (a .NET framework) which perfectly deals with this aspect of routing: https://github.com/NancyFx/Nancy/wiki/Defining-routes#pattern The issue is that in my project we're not using it... Nancy works as a perfect example of a tool that leaves exact definition of routing semantics to the client, instead of enforcing too tight rules on what is the route vs what is not.
You could Achieve this with just two routes:
[HttpGet("/api/experimental/cars/")]
public Task<List<Car>> SearchCars([FromQuery] string nameFilter = "", [FromQuery] int rating = 1)
and
[HttpGet("/api/experimental/cars/{carId}")]
public Task<Car> CarById([FromRoute] string carId)
I.e one route which brings the entire set back but can be filtered accordingly and one the brings back a single Car object by Id.
You will notice that the SearchCars method doesn't include the parameters in the route, FromQuery will catch these anyway.
EDIT:
if your request becomes complex it can be nice to define a custom request object type to wrap all your filters together:
public class MyRequestObject
{
public string NameFilter {get;set;}
public int Rating {get;set;}
}
then:
[HttpGet("/api/experimental/cars/")]
public Task<List<Car>> SearchCars([FromQuery] MyRequestObject requestParams)
Take a look at the following suggested routes that when tested do not conflict with each other and still allow for all the actions to be segregated.
[Route("api/experimental/cars")]
public class CarsController : Controller {
//GET api/experimental/cars
[HttpGet("")]
public IActionResult AllCars() { ... }
//GET api/experimental/cars/123
[HttpGet("{carId}")]
public IActionResult CarById(string carId) { ... }
//GET api/experimental/cars/named/Maz
//GET api/experimental/cars/named?filter=Maz
[HttpGet("named/{filter?}")]
public IActionResult CarsByNameFilter(string filter = "") { ... }
//GET api/experimental/cars/filtered?rating=2&name=Maz
//GET api/experimental/cars/filtered?rating=2
//GET api/experimental/cars/filtered?name=Maz
[HttpGet("filtered")]
public IActionResult CarsByNameAndRatingFilter(string name = "", int rating = 1) { ... }
}
My experience with this topic tells me that the best way to implement the APIs I wanted is to have two methods:
class CarsController {
// [HttpGet("/api/experimental/cars/")]
[HttpGet("/api/experimental/cars/{carId}")]
public Task<IEnumerable<Car>> CarById([FromRoute] string carId)
{
if (carId == null)
return GetAllCars();
else
return GetCarWithId(carId);
}
// [HttpGet("/api/experimental/cars/{nameFilter?}")]
[HttpGet("/api/experimental/cars/{nameFilter?}/{rating?}")]
public Task<IEnumerable<Car>> CarsByNameAndRatingFilter([FromQuery] string nameFilter = "", [FromQuery] int rating = 1)
{
// TODO Validate the combination of query string parameters for your specific API/business rules.
var filter = new Filter {
NameFilter = nameFilter,
Rating = rating
};
return GetCarsMatchingFilter(filter);
}
}
The first API is almost trivial. Even though returning a single item within a wrapping collection object may not look nice, it minimizes the number of API methods (which I personally am fine with).
The second API is trickier: in a way, it works as the façade pattern. I.e. that API will respond to pretty much all the possible /api/experimental/cars? based routes. Therefore, we need to very carefully validate the combination of received arguments before doing the actual work.

Attempting to generalize a authentication (Including parameter changing)

In our MVC project we are attempting to make everything as generic as possible.
Because of this we want to have one authentication class/method which covers all our methods.
As a example: The following code is a MVC class which can be called to from a client
public class Test
{
public void Test()
{
}
public int Test2(int i)
{
return i
}
public void Test3(string i)
{
}
}
A customer of our webservice can use a service reference to get access to Test(), Test2() and Test3().
Now i'm searching for a class, model, interface or anything else which I can use to alter the access to the method (Currently using [PrincipalPermission] attribute) as well as alter the parameter value.
Example:
Customer A calls Test2(150)
The class/method checks whether Customer A has access to Test2. The class/method validates the user but notices that the user does not have access to 150. He only has access to 100.So the class/method sets the parameter to 100 and lets it follow through on it's journey.
Customber B class Test()
The class/method checks whether Customer B has access to Test. After validation it shows that the user does not have access so it throws a SecurityException.
My question:
In what class, interface, attribute or whatever can I best do this?
(ps. As example i've only used authentication and parameter handling, but we plan to do a lot more in this stage.)
Edit
I notice most, if not all, assume I'm using actionResults. So i'd like to state that this is used in a webservice where we provide our customers with information from our database. In no way will we come in contact with a ActionResult during the requests to our webservice. (Atleast, not our customers)
Authentication can also be done through an aspect. The aspect oriented paradigm is designed to honor those so-called cross-cutting concerns. Cross-cutting concerns implemented in the "old-fashioned" oo-way make your business logic harder to read (like in Nick's example above) or even worse to understand, because they don't bring any "direct" benefit to your code:
public ActionResult YourAction(int id) {
if (!CustomerCanAccess(id)) {
return new HttpUnauthorizedResult();
}
/* the rest of your code */
}
The only thing you want here is /* the rest of your code */ and nothing more.
Stuff like logging, exception handling, caching and authorization for example could be implemented as an aspect and thus be maintained at one single point.
PostSharp is an example for an aspect-oriented C# framework. With PostSharp you could create a custom aspect and then annotate your method (like you did with the PrincipalPermissionAttribute). PostSharp will then weave your aspect code into your code during compilation. With the use of PostSharp aspects it would be possible to hook into the method invocation authenticating the calling user, changing method parameters or throw custom exceptions (See this blog post for a brief explanation how this is implemented).
There isn't a built-in attribute that handles this scenario.
I find it's usually best to just do something like this:
public ActionResult YourAction(int id) {
if (!CustomerCanAccess(id)) {
return new HttpUnauthorizedResult();
}
/* the rest of your code */
}
This is as simple as it gets and easy to extend. I think you'll find that in many cases this is all you need. It also keeps your security assertions testable. You can write a unit test that simply calls the method (without any MVC plumbing), and checks whether the caller was authorized or not.
Note that if you are using ASP.Net Forms Authentication, you may also need to add:
Response.SuppressFormsAuthenticationRedirect = true;
if you don't want your users to be redirected to the login page when they attempt to access a resource for which they are not authorized.
Here's how I've made my life simpler.
Never use simple values for action arguments. Always create a class that represents the action arguments. Even if there's only one value. I've found that I usually end up being able to re-use this class.
Make sure that all of teh properties of this class are nullable (this keeps you from running into default values (0 for integers) being automatically filles out) and thatallowable ranges are defined (this makes sure you don't worry about negative numbers)
Once you have a class that represents your arguments, throwing a validator onto a property ends up being trivial.
The thing is that you're not passing a meaningless int. It has a purpose, it could be a product number, an account number, etc. Create a class that has that as a property (e.g An AccountIdentifier class with a single field called 'id). Then all you have to do is create a [CurrentUsedCanAccessAccountId] attribute and place it on that property.
All your controller has to do is check whether or not ModelState.IsValid and you're done.
There are more elegant solutions out there, such as adding an action filter to the methods that would automatically re-direct based on whether or not the user has access to a specific value for the parameter, but this will work rather well
First, just to say it, that your own methods are probably the most appropriate place to handle input values (adjust/discard) - and with the addition of Authorize and custom filter actions you can get most done, and the 'MVC way'. You could also go the 'OO way' and have your ITest interface, dispatcher etc. (you get more compiler support - but it's more coupled). However, let's just presume that you need something more complex...
I'm also assuming that your Test is a controller - and even if it isn't it can be made part of the 'pipeline' (or by mimicking what MVC does), And with MVC in mind...
One obvious solution would be to apply filters, or action filters via
ActionFilterAttribute
Class
(like Authorize etc.) - by creating your own custom attribute and
overriding OnActionExecuting etc.
And while that is fine, it's not going to help much with parameters manipulation as you'd have to specify the code 'out of place' - or somehow inject delegates, lambda expressions for each attribute.
It is basically an interceptor of some sort that you need - which allows you to attach your own processing. I've done something similar - but this guy did a great job explaining and implementing a solution - so instead of me repeating most of that I'd suggest just to read through that.
ASP.NET MVC controller action with Interceptor pattern (by Amar, I think)
What that does is to use existing MVC mechanisms for filters - but it exposes it via a different 'interface' - and I think it's much easier dealing with inputs. Basically, what you'd do is something like...
[ActionInterceptor(InterceptionOrder.Before, typeof(TestController), "Test1")]
public void OnTest1(InterceptorParasDictionary<string, object> paras, object result)
The parameters and changes are propagated, you have a context of a sort so you can terminate further execution - or let both methods do their work etc.
What's also interesting - is the whole pattern - which is IOC of a
sort - you define the intercepting code in another class/controller
all together - so instead of 'decorating' your own Test methods -
attributes and most of the work are placed outside.
And to change your parameters you'd do something like...
// I'd create/wrap my own User and make this w/ more support interfaces etc.
if (paras.Count > 0 && Context.User...)
{
(paras["id"] as int) = 100;
}
And I'm guessing you could further change the implementation for your own case at hand.
That's just a rough design - I don't know if the code there is ready for production (it's for MVC3 but things are similar if not the same), but it's simplistic enough (when explained) and should work fine with some minor adjustments on your side.
I'm not sure if I understood your question, but it looks like a model binder can help.
Your model binder can have an interface injected that is responsible for determining if a user has permissions or not to a method, and in case it is needed it can change the value provided as a parameter.
ValueProviders, that implement the interface IValueProvider, may also be helpful in your case.
I believe the reason you haven't gotten ay good enough answer is because there are a few ambiguities in your question.
First, you say you have an MVC class that is called from a client and yet you say there are no ActionResults. So you would do well to clarify if you are using asp.net mvc framework, web api, wcf service or soap (asmx) web service.
If my assumption is right and you are using asp.net mvc framework, how are you defining web services without using action results and how does your client 'call' this service.
I am not saying it is impossible or that what you may have done is wrong, but a bit more clarity (and code) would help.
My advice if you are using asp.net mvc3 would be to design it so that you use controllers and actions to create your web service. all you would need to do would be to return Json, xml or whatever else your client expects in an action result.
If you did this, then I would suggest you implement your business logic in a class much like the one you have posted in your question. This class should have no knowledge of you authentication or access level requirements and should concentrate solely on implementing the required business logic and producing correct results.
You could then write a custom action filter for your action methods which could inspect the action parameter and determine if the caller is authenticated and authorized to actually access the method. Please see here for how to write a custom action filter.
If you think this sounds like what you want and my assumptions are correct, let me know and I will be happy to post some code to capture what I have described above.
If I have gone off on a tangent, please clarify the questions and we might be one step closer to suggesting a solution.
p.s. An AOP 'way of thinking' is what you need. PostSharp as an AOP tool is great, but I doubt there is anything postsharp will do for you here that you cannot achieve with a slightly different architecture and proper use of the features of asp.net mvc.
first create an attribute by inheriting from ActionFilterAttribute (system.web.mvc)
then override OnActionExecuting method and check if user has permission or not
this the example
public class CheckLoginAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!Membership.IslogedIn)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary
{
{ "area",""},
{ "action", "login" },
{ "controller", "user" },
{ "redirecturl",filterContext.RequestContext.HttpContext.Request.RawUrl}
});
}
}
}
and then, use this attribute for every method you need to check user permission
public class Test
{
[ChecklLogin]
public void Test()
{
}
[ChecklLogin]
public int Test2(int i)
{
return i
}
[ChecklLogin]
public void Test3(string i)
{
}
}

Categories

Resources