I want that action was available only to performance at the request of object of XHR. As I tried it to realize:
In the controller there is an action:
public string Act()
{
string view="";
if(Request.Headers["p"]!="p")
Response.Redirect("/",true);
else
view = GetActView();
return view;
}
It is caused by means of onclick of an event to which function is attached:
function updateDiv() {
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById('actdiv').innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open('GET', '/Act', true);
xmlhttp.setRequestHeader("p", "p");
xmlhttp.send();
}
But in addition to request from this function I can address to action, having collected in an address line of the browser website.com/Act value. This inadmissible behavior of my site. How to prevent such action of the user correctly ?
You can check that in the controller action using Request.IsAjaxRequest.For your action it can be done as below:
public string Act()
{
if(Request.IsAjaxRequest)
{
//AJAX work or response
}
//Non-AJAX work
}
You can even write a custom Attribute for this as below:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
var result = filterContext.Result as ViewResultBase;
if (result != null && result.Model != null)
{
filterContext.Result = new JsonResult
{
Data = result.Model,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
}
}
This can be applied on the controller method just like other ffilters as below:
[AjaxOnly]
public string Act()
{
}
You can do that by changing your request to 'POST' instead of 'GET'. Then the action should be decorated with [HttpPost] attribute like this:
[HttpPost]
public string Act()
{
}
Related
In my API I have a Create method in my controller that accepts all of the models fields, but in the method I'm excluding the ID field since on a create it's generated. But in Swagger it's showing the following.
Is there a way for it not to show the following part?
"id": 0
Is a viewmodel how I should go about this?
I tried the following, but can't get it to work.
public class PartVM
{
public string Name { get; set; }
}
public interface IPartService
{
Task<Part> CreatePart(PartVM part);
Task<IEnumerable<Part>> GetParts();
Task<Part> GetPart(int partId);
}
public class PartService : IPartService
{
private readonly AppDbContext _appDbContext;
public PartService(AppDbContext appDbContext)
{
_appDbContext = appDbContext;
}
public async Task<Part> CreatePart(PartVM part)
{
var _part = new Part()
{
Name = part.Name
};
var result = await _appDbContext.Parts.AddAsync(_part);
await _appDbContext.SaveChangesAsync();
return result.Entity;
}
}
Here's my controller.
[Route("api/[controller]")]
[ApiController]
public class PartsController : ControllerBase
{
private readonly IPartService _partService;
public PartsController(IPartService partService)
{
_partService = partService;
}
[HttpPost]
public async Task<ActionResult<Part>> CreatePart(PartVM part)
{
try
{
if (part == null)
return BadRequest();
var _part = new Part()
{
Name = part.Name
};
var createdPart = await _partService.CreatePart(_part);
return CreatedAtAction(nameof(GetPart),
new { id = createdPart.Id}, createdPart);
}
catch (Exception /*ex*/)
{
return StatusCode(StatusCodes.Status500InternalServerError, "Error creating new record in the database");
}
}
I'm getting a build error saying "CS1503 Argument 1: cannot convert from 'MusicManager.Shared.Part' to 'MusicManager.Server.Data.ViewModels.PartVM'".
It's refering to "_part" in this line "var createdPart = await _partService.CreatePart(_part);".
Any help is appreciated, thank you!
you have a CreatePart method which receives a PartVM model, but you are sending a Part Model to it
change your method to this :
public async Task<Part> CreatePart(Part part)
{
var result = await _appDbContext.Parts.AddAsync(_part);
await _appDbContext.SaveChangesAsync();
return result.Entity;
}
I want to implement audit logging in my .NET Core application.
Something like
[HttpPost, Auditing]
public dynamic SomeApiAction()
{
// API code here
...
}
The Attribute should be able to intercept the API call before and after execution in order to log.
Is there any such mechanism available in .net core as a part of the framework? I don't want to use any third-party component.
Please advise.
You can try Audit.WebApi library which is part of Audit.NET framework. It provides a configurable infrastructure to log interactions with your Asp.NET Core Web API.
For example using attributes:
using Audit.WebApi;
public class UsersController : ApiController
{
[HttpPost]
[AuditApi(IncludeHeaders = true)]
public IHttpActionResult Post()
{
//...
}
}
You can use CustomActionFilter for it like
public class CustomDemoActionFilter : Attribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
var controller = context.Controller as Controller;
if (controller == null) return;
var controllerName = context.RouteData.Values["controller"];
var actionName = context.RouteData.Values["action"];
var message = String.Format("{0} controller:{1} action:{2}", "onactionexecuting", controllerName, actionName);
var CurrentUrl = "/" + controllerName + "/" + actionName;
bool IsExists = false;
if(CurrentUrl=="/Home/Index")
{
IsExists=true;
}
else
{
IsExists=false;
}
if (IsExists)
{
//do your conditional coding here.
//context.Result = new RedirectToRouteResult(new RouteValueDictionary { { "controller", "Home" }, { "action", "Index" } });
}
else
{
//else your error page
context.Result = new RedirectToRouteResult(new RouteValueDictionary { { "controller", "Home" }, { "action", "Error" } });
}
//base.OnActionExecuting(context);
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
and just use this customactionfilter as attribute over your action method like
[HttpGet]
[CustomHMISActionFilter]
public IActionResult Registration()
{
//your code here
}
I'm stuck with binding an optional array in an ASP.NET Core Controller. The array contains elements of a custom type. Single elements of this type are bound with a custom model binder and validated in it.
Sample repo here: https://github.com/MarcusKohnert/OptionalArrayModelBinding
I get only two tests out of three working in the sample test project:
https://github.com/MarcusKohnert/OptionalArrayModelBinding/blob/master/OptionalArrayModelBindingTest/TestOptionalArrayCustomModelBinder.cs
public class TestOptionalArrayCustomModelBinder
{
private readonly TestServer server;
private readonly HttpClient client;
public TestOptionalArrayCustomModelBinder()
{
server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
client = server.CreateClient();
}
[Fact]
public async Task SuccessWithoutProvidingIds()
{
var response = await client.GetAsync("/api/values");
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
}
[Fact]
public async Task SuccessWithValidIds()
{
var response = await client.GetAsync("/api/values?ids=aaa001&ids=bbb002");
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
}
[Fact]
public async Task FailureWithOneInvalidId()
{
var response = await client.GetAsync("/api/values?ids=xaaa001&ids=bbb002");
Assert.Equal(System.Net.HttpStatusCode.BadRequest, response.StatusCode);
}
}
Controller:
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet]
public IActionResult Get(CustomIdentifier[] ids)
{
if (this.ModelState.IsValid == false) return this.BadRequest();
return this.Ok(ids);
}
}
Startup:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.ModelBinderProviders.Insert(0, new CutomIdentifierModelBinderProvider());
//options.ModelBinderProviders.Add(new CutomIdentifierModelBinderProvider());
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
ModelBinder:
public class CutomIdentifierModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
//if (context.Metadata.ModelType.IsArray && context.Metadata.ModelType == typeof(CustomIdentifier[]))
//{
// return new ArrayModelBinder<CustomIdentifier>(new CustomIdentifierModelBinder());
//}
if (context.Metadata.ModelType == typeof(CustomIdentifier))
{
return new BinderTypeModelBinder(typeof(CustomIdentifierModelBinder));
}
return null;
}
}
public class CustomIdentifierModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var attemptedValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ToString();
var parseResult = CustomIdentifier.TryParse(attemptedValue);
if (parseResult.Failed)
{
bindingContext.Result = ModelBindingResult.Failed();
bindingContext.ModelState.AddModelError(bindingContext.ModelName, parseResult.Message.Message);
}
else
{
bindingContext.Model = parseResult.Value;
bindingContext.Result = ModelBindingResult.Success(parseResult.Value);
}
return Task.CompletedTask;
}
}
The MVC default ArrayModelBinder of T binds optional arrays correctly and sets ModelState.IsValid to true. If I use my own CustomIdentifierModelBinder however ModelState.IsValid will be false. Empty arrays are not recognized as valid.
How can I solve this problem? Thanks in advance.
You are very close. Just customize behavior of built-in ArrayModelBinder for the case of missing parameter. If extracted value is an empty string just fill the model with an empty array. In all other cases you could call usual ArrayModelBinder.
Here is a working sample that passes all your 3 tests:
public class CutomIdentifierModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType.IsArray && context.Metadata.ModelType == typeof(CustomIdentifier[]))
{
return new CustomArrayModelBinder<CustomIdentifier>(new CustomIdentifierModelBinder());
}
return null;
}
}
public class CustomArrayModelBinder<T> : IModelBinder
{
private readonly ArrayModelBinder<T> innerModelBinder;
public CustomArrayModelBinder(IModelBinder elemeBinder)
{
innerModelBinder = new ArrayModelBinder<T>(elemeBinder);
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var attemptedValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ToString();
if (String.IsNullOrEmpty(attemptedValue))
{
bindingContext.Model = new T[0];
bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
return Task.CompletedTask;
}
return innerModelBinder.BindModelAsync(bindingContext);
}
}
The solution is the following code change, reflected in this commit:
https://github.com/MarcusKohnert/OptionalArrayModelBinding/commit/552f4d35d8c33c002e1aa0c05acb407f1f962102
I've found the solution by inspecting MVC's source code again.
https://github.com/aspnet/Mvc/blob/35601f95b345d0ef938fb21ce1c51f5a67a1fb62/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/SimpleTypeModelBinder.cs#L37
You'll need to check the valueProviderResult for None. If it's none then there is no parameter given and the ModelBinder binds correctly.
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == ValueProviderResult.None)
And also you register the provided ArrayModelBinder of T with your custom ModelBinder:
if (context.Metadata.ModelType.IsArray && context.Metadata.ModelType == typeof(CustomIdentifier[]))
{
return new ArrayModelBinder<CustomIdentifier>(new CustomIdentifierModelBinder());
}
I want that my page should be redirected to login page when the session expires Here is my code , I don't know what is wrong with it , bt it is not working , can anyone help?
code
public class SessionExpireAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
// check sessions here
if (HttpContext.Current.Session["username"] == null)
{
filterContext.Result = new RedirectResult("~/Account/Login");
return;
}
base.OnActionExecuting(filterContext);
}
}
namespace FinalTimesheetProject.Controllers
{
public class BaseController : Controller
{
static string startdate,enddate;
//
// GET: /Base/
[SessionExpire]
public ActionResult Index()
{
return View();
}
Heyaa , I had solved it , actually the code which i had posted earlier doesn't work with ajax post requests .. so i had written different condition for it , and now it works.. thanks.. and write this code into your controller because with class redirectToAction method won't work
code:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Session["username"] == null)
{
//CHECK REQUSET TYPE = GET
if (Request.RequestType.Equals("GET"))
{
//IF REQUEST IS AJAX
if (Request.IsAjaxRequest())
{
filterContext.Result = Json("SESSION_KILLED", JsonRequestBehavior.AllowGet);
return;
}
//NORMAL REQUSET
else
{
filterContext.Result = RedirectToAction("Login","Account");
return;
}
}
//REQUEST TYPE IS POST
else
{
filterContext.Result = Json("SESSION_KILLED", JsonRequestBehavior.AllowGet);
return;
}
}
base.OnActionExecuting(filterContext);
}
I want to implement a redirect unauthorized user with a check in the proper attribute. To do this I create a class attribute with a constructor with no parameters.
[AttributeUsage(AttributeTargets.Method)]
public class LoggedAttribute:Attribute
{
public LoggedAttribute()
{
//TODO
}
}
Now assign this attribute to all methods of action that requires authorization.
[Logged]
public ViewResult SendMessage()
{
return View();
}
I have a User model with boolean flag IsLoggedIn. How can I check this flag in the class attribute to redirect the user to the authentication page in case of an emitted flag ?
In the case of using a custom authorization attribute like below:
public class AuthorizeUserAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
//anything else you'd like to do like log it
return false;
}
}
}
and then you can redirect them by the following override:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
//disable the redirect
if(disabled)
{
//do something else
}else{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
controller = "Account",
action = "Login"
})
);
}
}
UPDATE: and you use it like this:
[AuthorizeUser]
public ActionResult myAction()
{
return View();
}