Unit Test for a View Attribute using Moq - asp.net

I am using Moq for unit testing and I would like to test for a view's attribute.
In this case the Authorize attribute.
Example View Code:
[Authorize(Roles = "UserAdmin")]
public virtual ActionResult AddUser()
{
// view logic here
return View();
}
So I would like to test the view attribute when I act on this view with a user that is in the role of UserAdmin and a user that is not in the role of user admin. Is there anyway to do this ?
Example Test:
[Test]
public void Index_IsInRole_Customer()
{
// Arrange
UserAdminController controller = _controller;
rolesService.Setup(r => r.IsUserInRole(It.IsAny<string>(), It.IsAny<string>())).Returns(false); // return false for any role
// Act
var result = controller.AddUser();
// Assert
Assert.IsNotNull(result, "Result is null");
}

Attributes are just metadata on the type, so they don't do anything unless the surrounding infrastructure make them do something (or better yet: the surrounding infrastructure does something based on the information in those attributes). That's what the ASP.NET MVC framework does when it executes a request.
That is not what you do when you create and invoke a Controller Action in a unit test, so unless you want to go to great lengths to invoke the Controller Action using a ControllerActionInvoker (at which point the test ceases to be a unit test and becomes an integration test) you can't directly test the behavior implied by the attribute.
You can, however, write a unit test that verifies that the attribute correctly decorates the Controller Action:
var attributes = typeof(UserAdminController)
.GetMethod("AddUser").GetCustomAttributes(true);
var result = attributes.OfType<AuthorizeAttribute>().Single();
Assert.AreEqual("UserAdmin", result.Roles);

When executing the test above the AuthorizeAttribute will not be taken into account (that is, no one will evaluate it). This is normally the responsibility of the ControllerActionInvoker (a class in System.Web.Mvc).
You might want to just trust that AuthorizeAttribute is correctly implemented. Then just use reflection to verify that the AuthorizeAttribute has been correctly defined on your action.

Related

Is it possible to validate a property using data-annotation asynchronously with ASP.NET Core?

I have an asp.net core 3.1 based project. I need to add a custom validation rule that will require a database call in ordered to determine the validity of the value.
For example, when creating a new user, I need to validate that there is no other username in the database with the same username before allowing the user to be created.
If I can create a custom attribute UniqueUsername, then I should be able to do something like this
public class UniqueUsername : ValidationAttribute
{
private readonly UserManager _manager = manager;
public UniqueUsername (UserManager manager)
{
_manager = manager;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string username = value.ToString();
if(_manager.Exists(username))
{
return new ValidationResult("The username provided belong to a different user.");
}
return ValidationResult.Success;
}
}
But, _manager.Exists(username) is a synchronous call. I want to avoid blocking the main thread, so I want a way to call await _manager.ExistsAsync(username) instead to avoid blocking the main thread.
Is there a way to create an attribute that would validate a single property and write errors "if any" to the ModelState?
If this isn't possible using data-annotation, is there an different way to validate property while writting errors to ModelState so when ModelState.IsValid() or TryValidateModel(model) are called, the attribute is called?
The data-annotations you add in your model are meant to validate the data present within the model (although some can also be translated into your database). These are meant to be reused even if you were to use your models on a client framework.
You can use the ModelState functions you mentioned to make async calls to your database. If you want to remove the logic from your controller, you can create utility functions to do so.
If you are open to third-party libraries, there is a great and popular validations library called Fluent Validation. Here is a documentation on how you can make async calls with it: https://docs.fluentvalidation.net/en/latest/async.html

ASP.NET MVC How does AuthorizeAttribute support checking Roles?

In my controllers, I have code like [Authorize(Roles = "Administrators")] annotated above some actions, and I want to know how AuthorizeAttribute uses the Roles parameter (the implementation of the checking mechanism). My goal is to create an extension of this class, called PrivilegeAttribute for example, so that I can annotate actions like [Privilege(Privileges = "read")]. In this class, I would check if the Role of the user has at least one of the privileges in this custom filter (read in this example). I have already created the association between roles and privileges in the code and in the database, and what I want help with is checking whether the role is associated to the privilege.
I tried seeing if that information is there in HttpContextBase.User.Identity but I couldn't find it.
Thank you.
If you don't need your own custom attribute and could live with using someone else attribute, than I would suggest to use the package Thinktecture.IdentityModel.Owin.ResourceAuthorization.Mvc as described here
Blog Post by Dominick Baier
and here
Git Hub Sample Code for the Package
so it basically works like this:
you put an attribute over your action like this:
[ResourceAuthorize("View", "Customer")]
The first argument is the name of the Action to check, the second one is the name of the attribute.
Then you derive from ResourceAuthorizationManager in your code and override the CheckAccessAssync Method
public class MyAuthorization : ResourceAuthorizationManager
{
public override Task<bool> CheckAccessAsync(ResourceAuthorizationContext context)
{
var resource = context.Resource.First().Value;
var action = context.Action.First().Value;
// getting the roles that are connected to that resource and action
// from the db. Context could of course be injected into the
// constructor of the class. In my code I assume that the table
// thank links roles, resources and actions is called Roles ToActions
using(var db = MyContext())
var roles = db.RolesToActions // Use your table name here
.Where(r => r.Resource == resource && r.Action == action).ToList();
foreach(var role in roles)
{
if(context.Principal.IsInRole(role.Name)
{
return Ok();
}
}
return Nok();
}
}
}
So I hope this helps. If you prefer to implement your own attribute however, than the source code from the ResourceAuthorization GitHub Repository should be a good starting point

PRG Pattern in ASP.Net MVC?

I'm new to ASP.Net MVC. In PHP, I always use the PRG pattern even when the post request was invalid. It was pretty easy with session flashes (also user friendly).
In ASP.Net MVC, however, I don't see an easy way to do PRG when the request is invalid. I could think of some ways, but I don't think they are good practices and put some extra unnecessary work.
Moreover, from a couple of articles that I've read, a PRG when the request was invalid was discouraged. If it's a bad practice, then what's the better way to handle unsuccessful post requests? Is it really better off without the PRG? And should I just let the rather annoying browser warnings when a user tries to refresh the page?
In Mvc, it's normal practice to handle your Post Actions as it follows:
[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult LoginForm(LoginViewModel loginViewModel)
{
if (!ModelState.IsValid)
return View("Login", loginViewModel);
return Redirect("/");
}
As you can see, the property ModelState.IsValid will tell you if the request is invalid, therefore giving you the ability to return the same view and display the error messages in the ValidationSummary when the Post request contains an error. This is the code for the View:
#using (Html.BeginForm("LoginForm", "Account"}))
{
#Html.ValidationSummary() // THIS WILL SHOW THE ERROR MESSAGES
#Html.AntiForgeryToken()
#Html.TextBoxFor(x => x.Email)
#Html.PasswordFor(x => x.Password)
<button type="submit">Submit</button>
}
We have been using PRG pattern in our asp.net mvc web apps for about 5 years. The main reason we adopted PRG was to support browser navigation (eg back, forward). Our web apps are used by customer and for front/back office operations. Our typical web page flow is starts with a login, then progresses via many list/detail view. We also incorporate partial views which also have their own viewmodel. List views will have links (GETS) for navigation. Detail views will have forms (POSTS) for navigation.
Keys aspects of our PRG:
We incorporate viewmodels so each view has a viewmodel (all data access is done in the viewmodel).
Each viewmodel has a set() & get() method to maintain the key data field values associated with the most recent instance of the view. The set/get values are persisted in sessionstate.
The set method has a parameter for each value that needs to be set. The get method is just called from the viewmodel constructor to populate the viewmodel's public "key" values.
The viewmodel will also have a public load() method that get all neccessary data for its view.
Our PRG pattern overview:
In controllers we have a separate GET method and a POST method for each action. The GET only displays a view; the POST processes the posted data.
For list (menu) views, the controller GET method calls the target view's set('item key values here') method, then invokes a RedirectToAction to to the target view's controller GET action.
The controller GET method will instantiate the viewmodel (thus causing get of set values), call its load method which uses the set/get key values to get it data, and returns the view/viewmodel.
The controller POST method will either have the viewmodel save the valid posted data then redirect to the next desired page (probably the previous list menu) -OR- if redisplay the current view if the data is invalid.
I have not documented all the PRG flow senarios that we implemented, but the above is the basic flow.
SAMPLE VIEWMODEL SET/GET METHODS
private void GetKeys() {
Hashtable viewModelKeys;
if (SdsuSessionState.Exists("RosterDetail"))
{
viewModelKeys = (Hashtable)SdsuSessionState.Get("RosterDetail");
EventId = (int)viewModelKeys["EventId"];
SessionNo = (int)viewModelKeys["SessionNo"];
viewModelKeys = null;
}
}
public static void SetKeys(int eventId, int sessionNo) {
Hashtable viewModelKeys = new Hashtable();
viewModelKeys.Add("EventId",eventId);
viewModelKeys.Add("SessionNo",sessionNo);
SdsuSessionState.Set("RosterDetail",viewModelKeys);
viewModelKeys = null;
}
SAMPLE CONTROLLER
[AcceptVerbs("Get")]
public ActionResult MenuLink(int eventId, int sessionNo, string submitButton) {
if (submitButton == RosterMenu.Button.PrintPreview) {
// P-R-G: set called viewmodel keys.
RosterDetail.SetKeys(eventId,sessionNo);
// Display page.
return RedirectToAction("Detail","Roster");
}
if (submitButton == RosterMenu.Button.Export) { etc ...}
}

asp.net mvc controller for masterpage? [duplicate]

I'm using a masterpage in my ASP.NET MVC project. This masterpage expects some ViewData to be present, which displays this on every page.
If I don't set this ViewData key in my controllers, I get an error that it can't find it. However, I don't want to set the ViewData in every controller (I don't want to say ViewData["foo"] = GetFoo(); in every controller).
So, I was thinking of setting this in a base controller, and have every controller inherit from this base controller. In the base controller default constructur, I set the ViewData. I found a similar approach here: http://www.asp.net/learn/MVC/tutorial-13-cs.aspx. So far so good, this works... but the problem is that this data comes from a database somewhere.
Now when I want to Unit Test my controllers, the ones that inherit from the base controller call its default constructor. In the default constructor, I initialize my repository class to get this data from the database. Result: my unit tests fail, since it can't access the data (and I certainly don't want them to access this data).
I also don't want to pass the correct Repository (or DataContext, whatever you name it) class to every controller which in turn pass it to the default controller, which I could then mock with my unit tests. The controllers in turn rely on other repository classes, and I would end up passing multiple parameters to the constructor. Too much work for my feeling, or am I wrong? Is there another solution?
I've tried using StructureMap but in the end I didn't feel like that is going to fix my problem, since every controller will still have to call the base constructor which will initialize the repository class, so I can't mock it.
This is a similar question but I find no satisfactory answer was given. Can I solve this in a neat way, maybe using StructureMap as a solution? Or should I jsut suck it and pass a Repository to every controller and pass it again to the base controller? Again, It feels like so much work for something so simple. Thanks!
I see two options:
First:
Set the ViewData for MasterPage in YourBaseController.OnActionExecuting() or YourBaseController.OnActionExecuted():
public class YourBaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Optional: Work only for GET request
if (filterContext.RequestContext.HttpContext.Request.RequestType != "GET")
return;
// Optional: Do not work with AjaxRequests
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
return;
...
filterContext.Controller.ViewData["foo"] = ...
}
}
Second:
Or create custom filter:
public class DataForMasterPageAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Optional: Work only for GET request
if (filterContext.RequestContext.HttpContext.Request.RequestType != "GET")
return;
// Optional: Do not work with AjaxRequests
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
return;
...
filterContext.Controller.ViewData["foo"] = ...
}
}
and then apply to your controllers:
[DataForMasterPage]
public class YourController : YourBaseController
{
...
}
I think the second solution is exactly for your case.

Access/use the same object during a request - asp.net

i have a HttpModule that creates an CommunityPrincipal (implements IPrincipal interface) object on every request. I want to somehow store the object for every request soo i can get it whenever i need it without having to do a cast or create it again.
Basically i want to mimic the way the FormsAuthenticationModule works.
It assigns the HttpContext.User property an object which implements the IPrincipal interface, on every request.
I somehow want to be able to call etc. HttpContext.MySpecialUser (or MySpecialContext.MySpecialUser - could create static class) which will return my object (the specific type).
I could use a extension method but i dont know how to store the object so it can be accessed during the request.
How can this be achieved ?
Please notice i want to store it as the specific type (CommunityPrincipal - not just as an object).
It should of course only be available for the current request being processed and not shared with all other threads/requests.
Right now i assign my CommunityPrincipal object to the HttpContext.User in the HttpModule, but it requires me to do a cast everytime i need to use properties on the CommunityPrincipal object which isnt defined in the IPrincipal interface.
I'd recommend you stay away from coupling your data to the thread itself. You have no control over how asp.net uses threads now or in the future.
The data is very much tied to the request context so it should be defined, live, and die along with the context. That is just the right place to put it, and instantiating the object in an HttpModule is also appropriate.
The cast really shouldn't be much of a problem, but if you want to get away from that I'd highly recommend an extension method for HttpContext for this... this is exactly the kind of situation that extension methods are designed to handle.
Here is how I'd implement it:
Create a static class to put the extension method:
public static class ContextExtensions
{
public static CommunityPrinciple GetCommunityPrinciple(this HttpContext context)
{
if(HttpContext.Current.Items["CommunityPrinciple"] != null)
{
return HttpContext.Current.Items["CommunityPrinciple"] as CommunityPrinciple;
}
}
}
In your HttpModule just put the principal into the context items collection like:
HttpContext.Current.Items.Add("CommunityPrincipal", MyCommunityPrincipal);
This keeps the regular context's user property in the natural state so that 3rd party code, framework code, and anything else you write isn't at risk from you having tampered with the normal IPrincipal stroed there. The instance exists only during the user's request for which it is valid. And best of all, the method is available to code as if it were just any regular HttpContext member.... and no cast needed.
Assigning your custom principal to Context.User is correct. Hopefully you're doing it in Application_AuthenticateRequest.
Coming to your question, do you only access the user object from ASPX pages? If so you could implement a custom base page that contains the cast for you.
public class CommunityBasePage : Page
{
new CommunityPrincipal User
{
get { return base.User as CommunityPrincipal; }
}
}
Then make your pages inherit from CommunityBasePage and you'll be able to get to all your properties from this.User.
Since you already storing the object in the HttpContext.User property all you really need to acheive you goal is a Static method that acheives your goal:-
public static class MySpecialContext
{
public static CommunityPrinciple Community
{
get
{
return (CommunityPrinciple)HttpContext.Current.User;
}
}
}
Now you can get the CommunityPrinciple as:-
var x = MySpecialContext.Community;
However it seems a lot of effort to got to avoid:-
var x = (CommunityPrinciple)Context.User;
An alternative would be an Extension method on HttpContext:-
public static class HttpContextExtensions
{
public static CommunityPrinciple GetCommunity(this HttpContext o)
{
return (CommunityPrinciple)o.User;
}
}
The use it:-
var x = Context.GetCommunity();
That's quite tidy but will require you to remember to include the namespace where the extensions class is defined in the using list in each file the needs it.
Edit:
Lets assume for the moment that you have some really good reason why even a cast performed inside called code as above is still unacceptable (BTW, I'd be really interested to understand what circumstance leads you to this conclusion).
Yet another alternative is a ThreadStatic field:-
public class MyModule : IHttpModule
{
[ThreadStatic]
private static CommunityPrinciple _threadCommunity;
public static CommunityPrinciple Community
{
get
{
return _threadCommunity;
}
}
// Place here your original module code but instead of (or as well as) assigning
// the Context.User store in _threadCommunity.
// Also at the appropriate point in the request lifecyle null the _threadCommunity
}
A field decorated with [ThreadStatic] will have one instance of storage per thread. Hence multiple threads can modify and read _threadCommunity but each will operate on their specific instance of the field.

Resources