I am implementing a Custom Authorize Attribute in MVC3. I am storing page level permissions in the database, and would like to pass my authorize attribute a Page ID. Something of the sort:
[CustomAuthorize(PageID = 1)]
public ActionResult About()
{
return View();
}
How do I implement the Authorize Attribute, as the AuthorizeCore only takes one argument in the override?
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
}
}
You would define a class-level variable to hold the PageID, and your attribute's constructor would take that as an argument. Or to use it like you have in your example, you would create a public property called PageID.
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public int PageID{get; set;}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//use PageID to do checks here.
}
}
Then within your AuthorizeCore, you would use that property/field value to do your checks.
(Custom User Type ) Just some tweaking
Test Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Authorise.Controllers
{
public class TestController : Controller
{
// GET: /Default1/
[CustomAuthorize(UserType = "Admin")]
public ActionResult Index()
{
return View();
}
}
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public string UserType { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (UserType == "Admin")
{
return true;
}
else
{
return false;
}
}
}
}
Test View
#{
ViewBag.Title = "Test";
}
<h2>Test</h2>
Account Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Authorise.Controllers
{
public class AccountController : Controller
{
//
// GET: /Account/
public ActionResult Index()
{
return View();
}
public ActionResult LogOn()
{
return View();
}
}
}
Account Logon View
#{
ViewBag.Title = "LogOn";
}
LogOn
Related
Given the following Web API controller action:
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
Executing the following request is not failing, even when the parameter in the query string does not exist:
http://localhost:22297/api/values?someinvalidparameter=10
Is there a way to ensure that all parameters in the query string are valid parameters for the action that's being invoked?
You can write an action filter that validates that all the query parameters are there in the action parameters and throws if not.
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace My.Namespace.Filters
{
/// <summary>
/// Action filter that checks that parameters passed in the query string
/// are only those that we specified in methods signatures.
/// Otherwise returns 404 Bad Request.
/// </summary>
public class ValidateQueryParametersAttribute : ActionFilterAttribute
{
/// <summary>
/// This method runs before every WS invocation
/// </summary>
/// <param name="actionContext"></param>
public override void OnActionExecuting(HttpActionContext actionContext)
{
//check that client does not use any invalid parameter
//but just those that are required by WS methods
var parameters = actionContext.ActionDescriptor.GetParameters();
var queryParameters = actionContext.Request.GetQueryNameValuePairs();
if (queryParameters.Select(kvp => kvp.Key).Any(queryParameter => !parameters.Any(p => p.ParameterName == queryParameter)))
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
}
}
In order for that to work with out of the box validation support nicely, I created my own action selector which makes it possible to bind URI parameters to complex type objects without duplication.
So, you can do the following with this action selector:
public class CarsByCategoryRequestCommand {
public int CategoryId { get; set; }
public int Page { get; set; }
[Range(1, 50)]
public int Take { get; set; }
}
public class CarsByColorRequestCommand {
public int ColorId { get; set; }
public int Page { get; set; }
[Range(1, 50)]
public int Take { get; set; }
}
[InvalidModelStateFilter]
public class CarsController : ApiController {
public string[] GetCarsByCategoryId(
[FromUri]CarsByCategoryRequestCommand cmd) {
return new[] {
"Car 1",
"Car 2",
"Car 3"
};
}
public string[] GetCarsByColorId(
[FromUri]CarsByColorRequestCommand cmd) {
return new[] {
"Car 1",
"Car 2"
};
}
}
Then, you can register an action filter to validate the user inputs to terminate request and return back a "400 Bad Request" response along with the validation error messages:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class InvalidModelStateFilterAttribute : ActionFilterAttribute {
public override void OnActionExecuting(HttpActionContext actionContext) {
if (!actionContext.ModelState.IsValid) {
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
Check out the below posts for more information about this action selector and how you can get it:
Complex Type Action Parameters with ComplexTypeAwareActionSelector in ASP.NET Web API - Part 1
Complex Type Action Parameters with ComplexTypeAwareActionSelector in ASP.NET Web API - Part 2
For .net core web-api it will be a little different:
public class ValidateQueryParametersAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
var parameters = actionContext.ActionDescriptor.Parameters.ToList();
var queryParameters = actionContext.HttpContext.Request.Query.Keys.ToList();
if (queryParameters.Any(queryParameter => !parameters.Any(p => p.Name == queryParameter)))
{
actionContext.Result = new JsonResult(new { HttpStatusCode.BadRequest });
}
}
}
I find some examples about this problem but I'm not able to use in my software have you got idea how to do it? And also can you explain me why I have got this problem?
No parameterless constructor defined for this object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.MissingMethodException: No parameterless constructor defined for this object.
SpotrStore.Domein
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using SportsStore.Entities;
namespace SportsStore.Concrete
{
public class EFDbContext : DbContext
{
public DbSet<Towar> Products { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SportsStore.Entities;
namespace SportsStore.Concrete
{
namespace SportsStore.Domain.Concrete
{
public class EFProductRepository
{
public EFDbContext context = new EFDbContext();
public IQueryable<Towar> Towar
{
get { return context.Products; }
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SportsStore.Entities;
namespace SportsStore.Concrete
{
public interface ITowarRepository
{
IQueryable<Towar> Towar { get; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
namespace SportsStore.Entities
{
[Table("Towar")]
public class Towar
{
[Key]
public int Id_tow { get; set; }
public string Nazwa { get; set; }
public string Opis { get; set; }
public string Cena { get; set; }
public int Id_kat { get; set; }
}
}
SportStore.WebUi
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SportsStore.Concrete;
using SportsStore.WebUI.Models;
namespace SportsStore.WebUI.Controllers
{
public class DefaultController : Controller
{
public ITowarRepository repository;
public DefaultController(SportsStore.Concrete.ITowarRepository repo)
{
repository = repo;
}
public ActionResult Index()
{
SomeView ViewModel = new SomeView
{
Towar = repository.Towar
.OrderBy(p => p.Id_kat)
};
return View(ViewModel);
}
}
}
-----------------------------------------------
#model SportsStore.WebUI.Models.SomeView
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#foreach (var item in #Model.Towar)
{
#item.Id_kat
}
---------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SportsStore.WebUI.Models
{
public class SomeView
{
public IEnumerable<SportsStore.Entities.Towar> Towar { get; set; }
}
}
By default the framework will call a parameterless constructor, which doesn't exist in your controller. A simple fix would be to add this parameterless constructor :
public DefaultController() : this(new SportsStore.Concrete.ITowarRepository()) { }
In addition to #dombenoit's answer, since your only constructor is:
public DefaultController(SportsStore.Concrete.ITowarRepository repo)
It looks like you are trying to use dependency injection to constructor inject an instance of your data repository. So possibly your problem is that you have some dependency injection framework you are trying to use, and isn't configured correctly?
So im new to MVC3 and expirimenting with DataAnnotations for the validation.
All is working fine clientside, but how do I get the serverside version working?
If I disable Javascript then there are no validations to be seen.
My Model looks like this
[Required(ErrorMessageResourceName = "Verplicht", ErrorMessageResourceType = typeof (ValidatieStrings))]
[Display(Name="Voorletters", ResourceType = typeof (VeldNaamStrings))]
public string Voorletters { get; set; }
My Controller looks like this
using System.Web.Mvc;
using inschrijven_werknemer.Models;
namespace inschrijven_werknemer.Controllers
{
public class HomeController : LocalizationController
{
public ActionResult Index()
{
return View(new MedewerkInfoModel());
}
}
}
And my View looks like this
#model inschrijven_werknemer.Models.MedewerkInfoModel
<div class="stap-div" id="stap2">
#Html.EditorForModel("MedewerkInfoModel")
</div>
What am I doing wrong?
you can do something like this... using Model.IsValid property.
So you could try this:
[HttpPost]
public ActionResult Index()
{
if (ModelState.IsValid)
{
return View(new MedewerkInfoModel());
}
return View();
}
A more detailed read is available here : https://stackoverflow.com/a/5969156/1182982 and https://stackoverflow.com/a/4760494/1182982
The reason I need this: In one of my controllers I want to bind all Decimal values in a different way than the rest of my application. I do not want to register a Model Binder in Global.asax (via ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());)
I have tried deriving from the DefaultModelBinder class and override its BindProperty method, but that only works for the model instance's immediate (not nested) Decimal properties.
I have the following example to demonstrate my problem:
namespace ModelBinderTest.Controllers
{
public class Model
{
public decimal Decimal { get; set; }
public DecimalContainer DecimalContainer { get; set; }
}
public class DecimalContainer
{
public decimal DecimalNested { get; set; }
}
public class DecimalModelBinder : DefaultModelBinder
{
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor.PropertyType == typeof (decimal))
{
propertyDescriptor.SetValue(bindingContext.Model, 999M);
return;
}
base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
}
public class TestController : Controller
{
public ActionResult Index()
{
Model model = new Model();
return View(model);
}
[HttpPost]
public ActionResult Index([ModelBinder(typeof(DecimalModelBinder))] Model model)
{
return View(model);
}
}
}
This solution only sets the Model's Decimal property to 999, but doesn't do anything to DecimalContainer's DecimalNested property. I realize this is because base.BindProperty is called in my DecimalModelBinder's BindProperty override, but I don't know how to convince the base class to use my Model Binder when dealing with decimal properties.
You could apply the model binder unconditionally in your Application_Start:
ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
and then have a custom authorization filter (yes, authorization filter as it runs before the model binder) that will inject into the HttpContext some value that could later be used by the model binder:
[AttributeUsage(AttributeTargets.Method)]
public class MyDecimalBinderAttribute : ActionFilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
filterContext.HttpContext.Items["_apply_decimal_binder_"] = true;
}
}
and then in your model binder test if the HttpContext contains the custom value befoire applying it:
public class DecimalModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (controllerContext.HttpContext.Items.Contains("_apply_decimal_binder_"))
{
// The controller action was decorated with the [MyDecimalBinder]
// so we can proceed
return 999M;
}
// fallback to the default binder
return base.BindModel(controllerContext, bindingContext);
}
}
Now all that's left is to decorate your controller action with the custom filter to enable the decimal binder:
[HttpPost]
[MyDecimalBinder]
public ActionResult Index(Model model)
{
return View(model);
}
Consider the two views. Which is preferred and what is a situation where you would use style 1 and not style 2 and vice versa?
Style 1 : View Injection
using System.Web.Mvc;
using Ninject;
namespace Views.Models.ViewClasses {
public abstract class CalculatorView : WebViewPage {
[Inject]
public ICalculator Calulator { get; set; }
}
}
And the view:
#inherits Views.Models.ViewClasses.CalculatorView
#{
ViewBag.Title = "Calculate";
}
<h4>Calculate</h4>
The calculation result for #ViewBag.X and #ViewBag.Y is #Calulator.Sum(ViewBag.X, ViewBag.Y)
Style 2: Using a Model
public class CalculatorModel {
// a constructor in here somewhere
public int X { get; set; }
public int Y { get; set; }
public int SumXY { get; set; }
}
The Controller:
public class CalculatorController : Controller {
private readonly ICalculator _calculator;
[Inject]
public CalculatorController (ICalculator calculator) {
_calculator = calculator;
}
public ActionResult Calculate(int x, int y)
{
return View(new CalculatorModel(x, y, _calculator.Sum(x, y))
}
...
The view:
#model CalculatorModel
#{
ViewBag.Title = "Calculate";
}
<h4>Calculate</h4>
The calculation result for #Model.X and #Model.Y is Model.SumXY
All I can really think of is:
If the calculator or whatever needs to be used a lot in the view, then view injection makes more sense as otherwise the model would have loads and loads of data otherwise models should be preferred?