I have my own custom Authorize Attribute and I am trying to check my controller methods to see if they have the correct roles in place. Now my custom authorize tag has database code in it.
The ways I am mocking it up don't seem to work since the reflection stuff I found seems to to just pass no arguments so my default constructor in the Authorize Attribute gets hit creating a new service layer object that creates a repository object(that kills the unit test).
var indexAction = typeof(Controller).GetMethod(method);
var authorizeAttributes = indexAction.GetCustomAttributes(typeof(AuthorizeAttribute), true);
//Assert
Assert.That(authorizeAttributes.Length > 0, Is.True);
foreach (AuthorizeAttribute att in authorizeAttributes)
{
Assert.That(att.Roles, Is.EqualTo(roles));
}
Constructors of my AutorizeAttribute
public MyAuthorize()
{
authorize = new ServiceLayer();
}
public MyAuthorize(IServicelayer layer)
{
authorize = layer;
}
the reflection stuff keeps calling my default constructor. How can I pass in a mock service layer or something?
Thanks
Have you looked at some of the Mocking Frameworks? I've used these to fake the http context etc in the past.
Here's another Stack Overflow post that might be able to help you...
https://stackoverflow.com/questions/37359/what-c-mocking-framework-to-use
I don't think the problem is with your code but what you are trying to test. What determines the roles that the attribute has?
If you are retrieving the roles from your service layer based on something passed into the attribute, your tests should confirm that the attribute exists on the action it is protecting ( part of the controller tests ), the appropriate calls are made to your service layer from the attribute ( part of the attribute tests ), and that the service layer returns the appropriate values for a specific request ( part of the controller tests ).
To ensure all of the parts work together, you will need to use integration tests that essentially mimic the entire request pipeline - something like Steve Sanderson's MvcIntegrationTest should simplify this http://blog.codeville.net/2009/06/11/integration-testing-your-aspnet-mvc-application/
Related
Currently I Have configured Identityserver4 as separated project + My WebAPI and store in DB Credentials in IdentityServer.
Now i have problem how to make CRUD(In my frontend API) to IdentityServer(I want from my API add Clients to IdentityServer)
How to make property?
From IdentityServer4.EntityFramework and IdentityServer4.EntityFramework.Storage, you have access to IConfigurationDbContext (once you've added the required services in ConfigureServices using e.g. AddConfigurationStore). Because this is registered as part of the Dependency Injection system, you can take a dependency on it in one of your controllers. e.g.:
public class ClientsController : ControllerBase
{
private readonly IConfigurationDbContext _configurationDbContext;
public ClientsController(IConfigurationDbContext configurationDbContext)
{
_configurationDbContext = configurationDbContext;
}
// ...
}
IConfigurationDbContext is an abstraction of a standard DbContext, with the following DbSet<T> properties:
Clients
IdentityResources
ApiResources
It also includes both SaveChanges and SaveChangesAsync - Everything one might expect from a DbContext. Because of all of this, you can CRUD each of these entities just like any other Entity Framework Core driven database.
One final thing to note is that there are both Models (in IdentityServer4.Storage) and Entities (in IdentityServer4.EntityFramework.Storage). There are also a few extension methods for mapping between these (e.g. ClientMappers.ToEntity).
Given all of this, you can create a Model inside of your controller (or perhaps somewhere much better encapsulated than directly there). Here's a basic example for creating a new Client:
var clientModel = new Client
{
ClientId = "",
ClientName = "",
// ...
};
_configurationDbContext.Clients.Add(clientModel.ToEntity());
await _configurationDbContext.SaveChangesAsync();
The Client class here comes from IdentityServer4.Models and is then converted to an Entity using a ToEntity extension method I hinted at above. Working with a Model and converting to an Entity is simpler than trying to manipulate an Entity directly - If you're interested, you can see the mapping that takes place here.
This works in the same way for ApiResources, IdentityResources, etc. Use the source code links I've provided if you want to find out more about those specifically, but the information I've provided here should have you covered.
In order to use IdentityServer4 and IdentityServer4.EntityFramework in your API project, you can just add the two references to your API project. After that, you can configure the DI in the same way (using AddIdentityServer in ConfigureServices), but you don't need to add the middleware (using UseIdentityServer in Configure). You can even just use AddIdentityServer().AddConfigurationStore(...) to set up the relevant services, as you don't need a signing key, etc.
One way you can do this is by bootstrapping the ID4 Quickstart (tutorial located here):
http://docs.identityserver.io/en/release/quickstarts/3_interactive_login.html
Other option is to use their quickstart seeds located here to speed this up:
https://github.com/IdentityServer/IdentityServer4.Samples
Now if you want to implement restfull login there are constraints around it (i wanted to find out as well) check out this question:
IdentityServer 4 Restfull Login/Logout
I am building a test for an MVC5 controller method. I'm using moq for the test. What I'm interested in is how to test a controller method that requires authentication and uses the userid value not the username value to make decisions about what data to show to the browser/client.
From what I have researched so far, there is a considerable amount of code available to moq the username, but not much code for the userid value (in my case that looks like a Guid). I'm using ASP.Net Identity as the account management. I have OWIN added as well for Google and Facebook login.
I'm using dependency injection (using Unity) because it seems that that is about the only way to accomplish tests, plus DI enables the use of moq.
Here is an example of the test method that is looking for a 'NotNull' return from the controller method:
Mock<ModelObject> CreateModelObjectFromHelper()
{
var ci = new Mock<ClaimsIdentity>();
var myHelper = new Mock<MyHelper>();
myHelper.Setup(x => x.GetCurrentUserId(ci.Object)).Returns("333c188b-b33a-4233-83bd-5ea3a3333333");
return new Mock<ModelObject>(myHelper.Object);
}
[TestMethod]
public async Task ExampleController_Method_NotNull()
{
Mock<ModelObject> o = CreateModelObjectFromHelper();
ExampleController controller = new ExampleController(o.Object as IModelObject);
ViewResult result = await controller.MethodName() as ViewResult;
//check for non null result
Assert.IsNotNull(result);
}
The GetCurrentUserId method is where I query the User.Identity object for the userid using this code:
var userIdClaim = user.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
userIdValue = userIdClaim.Value.ToString();
And the method is supposedly getting replaced by moq. The GetCurrentUserId method is a virtual method in a helper class (MyHelper) that is the parameter of the constructor for the model object (ModelObject) that is the parameter of the constructor for the controller (ExampleController).
What happens in the debugger (Visual Studio 2013) for the test method is that the objects are created in the CreateModelObjectFromHelper method, but when the ExampleController is created at the line:
ExampleController controller = new ExampleController(o.Object as IModelObject);
The MyHelper moq'd object becomes null. I can see the object has a value before this statement, but at this statement, the MyHelper object becomes null...and the whole test fails. I assume it fails because it is difficult to call methods on an object that is null.
The question is...what causes this object to become null?
The other question is...maybe there is a better way to do this and if so, I'd sure be glad to hear a suggestion.
Thank you
It doesn't work like that. You try to create mock of a mock of a mock ...
If your controller depend only on the IModelObject, then only create Mock and set it's properties/methods to return what you need in the controller.
Without the code for IModelObject, and how it is used in the controller, it's hard to provide better example.
I'm presently working on a project that has been upgraded to Webapi2 from Webapi. Part of the conversion includes the switch to using attribute based routing.
I've appropriately setup my routes in the Global.asax (as follows)
GlobalConfiguration.Configure(config => config.MapHttpAttributeRoutes());
and removed the previous routing configuration.
I have decorated all of my API controllers with the appropriate System.Web.Http.RouteAttribute and System.Web.Http.RoutePrefixAttribute attributes.
If I inspect System.Web.Http.GlobalConfiguration.Configuration.Routes with the debugger I can see that all my expected routes are registered in the collection. Likewise the appropriate routes are available within the included generated Webapi Help Page documentation as expected.
Even though all appears to be setup properly a good number of my REST calls result in a 404 not found response from the server.
I've found some notable similarities specific to GET methods (this is all I've tested so far)
If a method accepts 0 parameters it will fail
If a route overrides the prefix it will fail
If a method takes a string parameter it is likely to succeed
return type seems to have no affect
Naming a route seems to have no affect
Ordering a route seems to have no affect
Renaming the underlying method seems to have no affect
Worth noting is that my API controllers appear in a separate area, but given that some routes do work I don't expect this to be the issue at hand.
Example of non-functional method call
[RoutePrefix("api/postman")]
public class PostmanApiController : ApiController
{
...
[HttpGet]
[Route("all", Name = "GetPostmanCollection")]
[ResponseType(typeof (PostmanCollectionGet))]
public IHttpActionResult GetPostmanCollection()
{
return Ok(...);
}
...
}
I expect this to be available via http://[application-root]/api/postman/all
Interestingly enough a call to
Url.Link("GetPostmanCollection", null)
will return the above expected url
A very similar example of method calls within the same controller where some work and some do not.
[RoutePrefix("api/machine")]
public class MachineApiController : ApiController
{
...
[HttpGet]
[Route("byowner/{owner}", Name = "GetPostmanCollection")]
public IEnumerable<string> GetByOwner([FromUri] string owner)
{
...
}
...
[HttpGet]
[Route("~/api/oses/{osType}")]
public IEnumerable<OsAndVersionGet> GetOSes([FromUri] string osType)
{
...
}
...
}
Where a call to http://[application-root]/api/machineby/ownername succeeds and http://[application-root]/api/oses/osType does not.
I've been poking at this far too long, any idea as to what the issue may be?
Check that you configure your HttpConfiguration via the MapHttpAttributeRoutes method before any ASP.NET MVC routing registration.
In accordance to Microsoft's CodePlex entry on Attribute Routing in MVC and Web API the Design section states:
In most cases, MapHttpAttributeRoutes or MapMvcAttributeRoutes will be
called first so that attribute routes are registered before the global
routes (and therefore get a chance to supersede global routes).
Requests to attribute routed controllers would also be filtered to
only those that originated from an attribute route.
Therefore, within the Global.asax (or where registering routes) it is appropriate to call:
GlobalConfiguration.Configure(c => c.MapHttpAttributeRoutes()); // http routes
RouteTable.Routes.MapRoute(...); // mvc routes
In my case it was a stupid mistake, I am posting this so people behind me making the same mistake may read this before they check everything else at quantum level.
My mistake was, my controller's name did not end with the word Controller.
Happy new year
I want to log visits only for some controllers (or routes) as it was possible with classic ASP.NET pages by checking/unchecking the 'log visits' checkbox in IIS.
Does anyone know if this is possible somehow? A solution without a custom logging component would be fantastic! Please share your knowledge, if you know how ;)
Thanks in advance
Create a BaseController which the controllers that you want to record data for inherit from. Then create an ActionFilter which overrides the OnActionExecuted method and apply it to the base controller. Something like this..
public class ActionExecutedFilter : System.Web.Mvc.ActionFilterAttribute
{
UnitOfWork unitOfWork= new UnitOfWork();
public override void OnActionExecuted(ActionExecutedContext filter)
{
Transaction tran = new Transaction();
tran.Controller = filter.ActionDescriptor.ControllerDescriptor.ControllerName;
tran.ActionName = filter.ActionDescriptor.ActionName;
tran.User = HttpContext.Current.User.Identity.Name;
tran.Date = DateTime.Now;
unitOfWork.TransactionRepository.Insert(tran);
unitOfWork.Save();
}
}
This will save to a database table called Transactions information for every time a action method is called on that controller, recording the user, controller and action method name. Obviously I just typed in the UnitOfWork method of saving to the database, you can just plug in whichever method you like. I usually keep these methods in a filters folder, add a using statement then add it to the controller like so;
[ActionExecutedFilter]
public class BaseController : Controller
{
}
Again, just make all the controller you wish to record data from inherit the BaseController.
You could also use something like Log4Net, but I find just doing it this way gets what I need. Whatever you think yourself.
http://dotnetdarren.wordpress.com/2010/07/29/logging-in-mvc-part-4-log4net/
A solution without a custom logging component would be fantastic!
Apart from basic IIS diagnostic logs, I cannot think of any ASP.Net MVC specific Logging features in IIS.
One simple solution what I want to offer is to write a HttpModule. In the HttpModule you can log the requests. Also if you want to have control on what to log and what not to, then based on Routes you can make that happen in HttpModule. Advantage with HttpModule is it is easy to plug in and also easy to remove.
Make HttpModule work only on certain routes
When it comes to logging itself, you can have your own custom logic to database or to log file. But you can opt for ELMAH or Log4Net or Enterprise Logging Application Block
In my current project we have a notification system. When an oject is added to another objects collection, an email is sent to those who are subscibed to the parent object. This happens on the object layer and not in the View or Controller.
Here's the problem:
Although we can say who created what with what information in the email, we cannot embed links to those objects in the email because in the object layer there is no access to a UrlHelper. To construct a UrlHelper you need a RequestContext, which again does not exist on the object layer.
Question:
I want to make a helper class to create the url's for me. How can I create an object that will generate these urls without a request context? Is it possible?
The problem is compounded by the fact that you don't want a relative URL in an email, you want an absolute email so you need to hard-code the domain too because there is no request to grab it from.
Another factor is that emails can outlive the current site structure by months or years so you need a kind of permalink, and thus a way to associate multiple Urls with a single action (additional routes). This latter issue is also a factor in SEO where you don't want to leave any page behind.
For now a static method on your controller UrlToActionX(params) sitting next to the method ActionX seems like the simplest workaround. All it does is the appropriate string.Format(...) on the id's of the strongly-typed parameters to generate the permanent Url. Add a static domain on the front, or a domain from the user object (since you know which domain they visit when they come to your site) and you have your email link.
It's not ideal but at least you now have only one place to maintain the Url generation.
IMHO: When it comes to permanent links to a changing web site sometimes it's better to rely on "configuration over convention". :-)
I'm not aware of a way to do this, you MUST have access to the routes at the very least to make your own helper. Unless your business objects know about the registered routes, you can't get away from doing some hard-coding.
Here is how you might limit the hard-coding of urls though...
Code in a url with all the relevant bits in your object's methods..
class Event
{
public void SendEmail()
{
var url = string.Format("http://myurl.com/r/Event?eventId={0}", EventId);
//send emails...
}
}
Note the /r/Event piece of the url. This would be a map to a RController that would be responsible for taking arbitrary, made-up links and sending a 301 Permanent Redirect and going through the route engine to create a real url using the current routes. This way you are only hard-coding a utility controller url and not to the ever evolving controller actions of your real pages.
class RController : Controller
{
public ActionResult Event(int eventId)
{
Response.StatusCode = (int)HttpStatusCode.MovedPermanently;
Response.RedirectLocation = Url.Action("Details", "Event", new { eventId = eventId });
return null;
}
public ActionResult Register(int eventId)
{
Response.StatusCode = (int)HttpStatusCode.MovedPermanently;
Response.RedirectLocation = Url.Action("Register", "Event", new { eventId = eventId });
return null;
}
}
It just feels a bit better than hard-coding a bunch of different controllers/actions that you might decide to rename later. Think of it as your own little TinyUrl like service.
You could define an interface with a method that takes whatever information is necessary to create a URL (object ids or whatever) and returns a URL. Write an implementation of that interface that uses the UrlHelper to do this work, and then supply this to your object layer (ideally with an IoC container).
You could use:
VirtualPathUtility.ToAbsolute(string.Format("~/r/Event?eventId={0}", id))
to resolve the url. Still not nice though.