asp mvc roles from httpcontext - asp.net-mvc-2

i want to pass current area name to authorization attribute, like:
[SexyAuthorize(Roles = Url.RequestContext.RouteData.Values["area"])]
public class FormsController : Controller
{
}
but Url is member of controller. how can i pass it other way?
i know that i can use User.InRole in each method, but i want do it for class. thx.

You can't pass dynamic values to an attribute like this. All values passed to an attribute in .NET need to be known at compile time. One possible workaround is to fetch this value in your custom implementation of the attribute as you have access to the HTTP context.
Something like:
[SexyAuthorize(RolesRouteParamName = "area")]
public class FormsController : Controller
{
...
}
and then:
public SexyAuthorizeAttribute: AuthorizeAttribute
{
public string RolesRouteParamName { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
var roles = httpContext.Request.RequestContext.RouteData.Value[RolesRouteParamName];
// TODO: continue with the implementation...
...
}
}

Related

Passing parent component to all child components in blazor via rendertree

I created an custom form component in blazor and inherited from the default EditForm component to add some functionality.
public class CustomForm : EditForm
I want to pass the instance of the form component to all its children, so a child can retrieve it via a cascading parameter like so
[CascadingParameter]
public CustomForm Form { get; set; }
I took over the BuildRenderTree Method of the default Editform
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
Debug.Assert(EditContext != null);
// If _editContext changes, tear down and recreate all descendants.
// This is so we can safely use the IsFixed optimization on CascadingValue,
// optimizing for the common case where _editContext never changes.
builder.OpenRegion(EditContext.GetHashCode());
builder.OpenElement(0, "form");
builder.AddMultipleAttributes(1, AdditionalAttributes);
builder.AddAttribute(2, "onsubmit", _handleSubmitDelegate);
builder.OpenComponent<CascadingValue<EditContext>>(3);
builder.AddAttribute(4, "IsFixed", true);
builder.AddAttribute(5, "Value", EditContext);
builder.AddAttribute(6, "ChildContent", ChildContent?.Invoke(EditContext));
builder.CloseComponent();
builder.CloseElement();
builder.CloseRegion();
}
But i do not know how to manipulate this code to achieve my goal.
It's possible to pass any object as cascading value so you can override the BuildRenderTree like this and the CustomForm instance will be passed to the child components. Explicit cast to RenderFragment is needed to create delegate of this type, otherwise CascadingValue<>.SetParametersAsync will throw an invalid cast exception.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Rendering;
namespace BlazorTest
{
public class CustomForm : EditForm
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenRegion(0);
builder.OpenComponent<CascadingValue<CustomForm>>(1);
builder.AddAttribute(2, "Value", this);
builder.AddAttribute(3, "ChildContent", (RenderFragment)base.BuildRenderTree);
builder.CloseComponent();
builder.CloseRegion();
}
}
}
I tested this with these components:
CustomFormComponent.razor
<h3>CustomFormComponent</h3>
#code {
private CustomForm _form;
[CascadingParameter]
public CustomForm Form
{
get => _form;
set
{
_form = value;
Console.WriteLine("CustomForm set in CustomFormInput");
}
}
}
TestPage.razor
#page "/test"
<CustomForm Model=model>
<CustomFormComponent />
</CustomForm>
#code {
private AModel model = new();
private class AModel
{
public string Name { get; set; }
}
}
I just want to add that I'm not an expert in this and I'm not sure if you should do it this way. Maybe it would be better to use EditForm as a child component of the CustomForm because you don't have to worry about BuildRenderTree method when using razor markup.
<CascadingValue Value=this>
<EditForm Model=model>
#ChildContent
</EditForm
</CascadingValue>

Derived attribute with AsTajson call in the custom service

I use .net5 and .netStandard from nuget. The structure of the solution is simple - class library with ecomodel and webapi project.
I've registers custom service in the EcoSpace1.cs as it was advised by eco gurus long, long time ago.
public interface IMyService
{
int Class1Count();
}
public class MyServiceClass : IMyService
{
private IEcoServiceProvider ServiceProvider { get; set; }
public MyServiceClass(IEcoServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
public int Class1Count()
{
var v = ServiceProvider.GetEcoService<IOclService>().Evaluate("Class1.allInstances->size");
return (int)v.AsObject;
}
}
The rule for a webapi project's controller- inherit from the Controller class - due to the Swashbuckle.AspNetCore (swagger) usage. Swagger shows errors if I inherit a controller from the ModelDrivenControllerBase
But the code above is OK, the GET works perfect:
public class MySecondEcoServiceController : Controller
{
[HttpGet]
public int Get()
{
using (EcoSpace1 es=new EcoSpace1())
{
es.Active = true;
int r = es.MyService.Class1Count();
return r;
}
}
}
It works till I tried to add another method into the IMyService and to get json. I tried AsTajson by adding derived attribute to the Class1 with DerivationOcl.
Class1.allInstances->first.AsTaJson( 'SampleViewModel', false )
or
self.AsTaJson( 'SampleViewModel', false )
In the MyServiceClass the implementation of the Get is:
Class1 v = (Class1)ServiceProvider.GetEcoService<IOclService>().Evaluate("Class1.allInstances->first").AsObject;
json = v.Attribute2;
If I tried GET this value - exception:
Eco.FrameworkImpl.Ocl.EBoldOCLError: 'bughuntinfo internaleval:84 es seems fine.Object reference not set to an instance of an object.'
What is the proper way (or EcoService?) to get values returned by TaJson?
Not sure but please check that you have initiated use of ViewModels once for your EcoSpace type:
ViewModelDefinitionsInApplication.Init(_es);

MVC 5 how to specify constraints using attribute routing

I'm trying to do full attribute routing, without conventional routing, and trying to tell my routes which area they belong to based on the current domain.
In convention routing, I can specify my object constraints with this as an example:
context.MapRoute(
"MyRouteName",
"admin/sign-in",
new { controller="AdminController", action="SignIn" },
new { SitePermitted = new SiteConstraint("Admin") } // <-- how do I do this exact line of code but in attribute routing
);
Where SiteConstraint inherits from IRouteConstraint. How do I do the same thing, but using attribute routing? I am looking for something like this:
[AreaName("Admin")]
[Route("admin/sign-in")]
[new SiteConstraint("Admin")]
public ActionResult SignIn(...) {...}
Where MyConstraint has a Match method that gets the current http request and if its domain is "myadmindomain.com", then Match method returns true, and MVC executes this route given that the user is on myadmindomain.com/admin/sign-in.
What you want to do requires the use of the class RouteFactoryAttribute, in MVC 5 inhering from that class you can use your SiteConstraint but using attribute routing. So you can have something like:
public class SiteRouteAttribute : RouteFactoryAttribute
{
public SiteRouteAttribute (string template, string sitePermitted) : base(template)
{
SitePermitted = sitePermitted;
}
public override RouteValueDictionary Constraints
{
get
{
var constraints = new RouteValueDictionary();
constraints.Add("site", new SiteConstraint(SitePermitted));
return constraints;
}
}
public string SitePermitted
{
get;
private set;
}
}
Then in your controller you can have:
[SiteRoute("somepath/{somevariable}/{action=Index}", "Admin")]
public class MyController : Controller
{
public ActionResult Index()
{
....
}
}
Take a look at Jon Galloway's post which has a workable example

How to pass dynamic variable to Action Filter in ASP.NET MVC

I would like to use a variable to pass a dynamic value to my action filter. I thought it would be something like this:
[MessageActionFilter(message = "User is updating item: " & id)]
public ActionResult doSomething(int id)
{
// do something
}
However, it seems that the parameter must be a constant value. Therefore, my question is how do I get the variable to my action filter?
You can get the parameter values in OnActionExecuting using the ActionExecutingContext.ActionParameters property.
It's just a pseudo code, but for example you can retrive the parameter named id
public class MessageActionFilter: ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var response = filterContext.HttpContext.Response;
var parameterValue = filterContext.ActionParameters.SingleOrDefault(p => p.Key == "id");
// check if not null before writing a message
response.Write(this.Message + parameterValue); // prints "User is updating item: <idvalue>"
}
public string Message {get; set;}
}
Tell me if it helps.

Ambiguous action methods in MVC 2

I'm having some problems with ambiguous action methods in MVC 2. I've tried implementing the solution found here: ASP.NET MVC ambiguous action methods, but that simply gives me a "The resource cannot be found" error as it thinks I'm trying to invoke the action method I don't want to invoke. The RequiredRequestValueAttribute class I'm using is the exact same one as what was in the other question's solution:
public class RequireRequestValueAttribute : ActionMethodSelectorAttribute
{
public RequireRequestValueAttribute(string valueName)
{
ValueName = valueName;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
return (controllerContext.HttpContext.Request[ValueName] != null);
}
public string ValueName { get; private set; }
}
My action methods are:
//
// GET: /Reviews/ShowReview/ID
[RequireRequestValue("id")]
public ActionResult ShowReview(int id)
{
var game = _gameRepository.GetGame(id);
return View(game);
}
//
// GET: /Reviews/ShowReview/Title
[RequireRequestValue("title")]
public ActionResult ShowReview(string title)
{
var game = _gameRepository.GetGame(title);
return View(game);
}
Right now, I'm trying to use the int id version, and instead it's invoking the string title version.
This solution assumes that you must absolutely use the same URL regardless of if you're selecting by ID or name, and that your route is set up to pass a value to this method from the URL.
[RequireRequestValue("gameIdentifier")]
public ActionResult ShowReview(string gameIdentifier)
{
int gameId;
Game game = null;
var isInteger = Int32.TryParse(gameIdentifier, out gameId);
if(isInteger)
{
game = _gameRepository.GetGame(gameId);
}
else
{
game = _gameRepository.GetGame(gameIdentifier);
}
return View(game);
}
Update: According to Microsoft: "Action methods cannot be overloaded based on parameters. Action methods can be overloaded when they are disambiguated with attributes such as NonActionAttribute or AcceptVerbsAttribute."