passing parameter from custom filter to web api controller - asp.net-web-api

I am working on a web application in which we are using web-api and oAuth2.
I had stored my UserId in front-end but now for security reason I am storing my UserId in backend against the token generated from oAuth2.
So I have around 800 api's in my application all of them are POST api's and the data is passing in those api's like below
Type 1
[HttpPost]
[Authorize]
[ActionName("GetList")]
[Filters.AuthorizeLoginApi()]
public List<BusinessEntities.Admin.Users> GetList(Dictionary<string, string> Parameters)
{
try
{
if (Parameters != null)
{
BusinessLayer.IAdmin.IUsers a = (BusinessLayer.IAdmin.IUsers)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IUsers));
return a.GetList(Convert.ToString(Parameters["LoginText"]), Convert.ToString(Parameters["Name"])
, Convert.ToString(Parameters["Email"]), Convert.ToInt32(Parameters["UserTypeId"]), Convert.ToString(Parameters["IsActive"])
, Convert.ToInt32(Parameters["UserId"])); /*(LoginText, Name, Email, UserTypeId, IsActive, UserId);*/
}
else
{
return new List<BusinessEntities.Admin.Users>();
}
}
catch (Exception ex)
{
Utils.Logger.Instance.LogException(ex);
return new List<BusinessEntities.Admin.Users>();
}
}
In the above code I have a Dictionary parameter in which I am storing my userId
Type 2
[HttpPost]
[Authorize]
[ActionName("Delete")]
[Filters.AuthorizeLoginApi()]
public SPResponse Delete(BusinessEntities.Admin.Users item)
{
SPResponse response = new SPResponse();
try
{
//item.ModifiedByUserId is my UserId
BusinessLayer.IAdmin.IUsers a = (BusinessLayer.IAdmin.IUsers)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IUsers));
response = a.Delete(item);
}
catch (Exception ex)
{
response.ReturnMessage = ex.Message;
}
return response;
}
I am doing custom validation in each and every api calls like below
public class AuthorizeLoginApi : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
//Code to Get userId from database
//int UserId = data coming from db
//pass the above UserId Parameter into every apis as UserId/ModifiedByUserId
}
}
Now I want to Pass UserId/ModifiedByUserId from OnActionExecuting filter method into my respective API's
How can I achieve this

Related

Handle Sharp In Controller And Get Id

There was a jsp application. I have just converted to spring boot application. I want to continue to use same links to handle company's information. Old urls are like /Dashboard.jsp#/company/10712. I have tried to handle company id but it didn't wook. How can I handle company id ?
#GetMapping("/Dashboard.jsp#/company/{id}")
public void try(#PathVariable String id) {
System.out.println(id);
}
I have also tried;
adding
server.tomcat.relaxed-path-chars=#
in application properties.
#RequestMapping(value = ERROR_PATH, produces = "text/html")
public Object errorHtml(HttpServletRequest request, HttpServletResponse response) {
if (response.getStatus() == HttpStatus.NOT_FOUND.value()) {
return new ModelAndView("redirect:" + StringUtils.getBaseUrl(request) + "/?page=error", HttpStatus.FOUND);
} else {
return new ModelAndView("redirect:" + StringUtils.getBaseUrl(request) + "/?page=error");
}
}
This function handle 404.
request.getAttribute("javax.servlet.forward.request_uri")
returns /esir/Dashboard.jsp. There is no # and others.

unable to return a page from Restcontroller

I am using stripe as a payment gateway. I just need to return a page from Webhook controller which is a rest controller. I know Restcontroller should not return a view but can't see any other option except this. Now I am using ModelandView interface to return a view but unable to do that. So please tell me that how can I return a view from restcontroller and what is wrong in this code.
#RestController
public class StripeWebhookController {
#Autowired
private FoodhubServiceImpl service;
#Autowired
private Payment payment;
private String endpointSecret="some endpointSecret";
#PostMapping("/foodhub/endpoint")
public ModelAndView handleStripeEvents(#RequestBody String payload, #RequestHeader("Stripe-Signature") String sigHeader, HttpServletRequest request) {
if(sigHeader == null) {
System.out.println("sigheader is null");
return null;
}
Event event;
// Only verify the event if you have an endpoint secret defined.
// Otherwise use the basic event deserialized with GSON.
try {
event = Webhook.constructEvent(
payload, sigHeader, endpointSecret
);
} catch (SignatureVerificationException e) {
// Invalid signature
System.out.println("Webhook error while validating signature.");
System.out.println(e);
return null;
}
// Deserialize the nested object inside the event
EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer();
StripeObject stripeObject = null;
if (dataObjectDeserializer.getObject().isPresent()) {
stripeObject = dataObjectDeserializer.getObject().get();
} else {
// Deserialization failed, probably due to an API version mismatch.
// Refer to the Javadoc documentation on `EventDataObjectDeserializer` for
// instructions on how to handle this case, or return an error here.
}
// Handle the event
switch (event.getType()) {
case "payment_intent.succeeded":
PaymentIntent paymentIntent = (PaymentIntent) stripeObject;
System.out.println("Payment succeeded for "+paymentIntent.getAmount());
handlePaymentIntentSucceeded(paymentIntent);
// Then define and call a method to handle the successful payment intent.
break;
default:
System.out.println("Unhandled event type: " + event.getType());
break;
}
ModelAndView mv = new ModelAndView();
mv.setViewName("payment-success.jsp");
return mv;
}

Web API Validation for Model Bound in GET request

I have created a custom Model Binder to read the data from the URI in a specific format
public ResponseObject Get([FromUri(BinderType = typeof(CustomModelBinder)]ProductFilter product
{...}
public class ProductFilter
{
[Required(ErrorMessage = #"Name is required")]
public string Name { get; set; }
}
public class CustomModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
//Code to convert the uri parameters to object
return true;
}
}
In the above example, i need the name to be passed from the client before executing the Action.
But, I am unable to run the in-built validations on the Product class using this?
Any ideas?
I wrote in a custom action filter and I registered this action filter in the GlobalConfiguration for all the services. The action filter hooks on to onActionExecuting, looks for the validation in the bound arguments.
bool isValid;
foreach (var item in actionContext.ActionArguments)
{
var parameterValue = item.Value;
var innerContext = new ValidationContext(parameterValue);
if(parameterValue != null)
{
var innerContext = new ValidationContext(parameterValue);
isValid = Validator.TryValidateObject(parameterValue, innerContext, results, true);
}
}
//If not valid, throw a HttpResponseException
if(!isValid)
throw new HttpResponseException(HttpStatusCode.BadRequest);
else
base.onActionExecuting(actionContext);
With more tuning, the exact validation message can be retrieved from the validation context and sent as the response message.
I was also able to extend this to having validation attributes on the parameters themselves, thereby giving more flexibility to my Api

Appropriate pattern for setting request object properties from POST request with MVC3?

With incoming POST requests to my MVC3 application, I want to validate the incoming request parameters. If an invalid parameter exists, an exception is thrown.
Given the following object:
public class ActionRequest
{
public string ActionRequestPassword { get; set; }
public bool EnableNewsfeedAppPool { get; set; }
}
With incoming post requests, I want to initialize the object with the appropriate properties via:
public class NewsfeedAppPoolController : Controller
{
[ActionName("EnableAppPool"), AcceptVerbs(HttpVerbs.Post)]
[ValidateInput(false)]
[NoCache]
public ActionResult EnableAppPool(FormCollection formCollection)
{
Models.ActionRequest actionRequest = ValidatePOSTRequest(formCollection);
// do things with actionRequest
return null;
}
private Models.ActionRequest ValidatePOSTRequest(FormCollection formCollection)
{
try
{
Type actionRequestType = typeof(Models.ActionRequest);
System.Reflection.PropertyInfo propertyInfo = null;
object systemActivatorObject = Activator.CreateInstance(actionRequestType);
foreach (var key in formCollection.AllKeys)
{
propertyInfo = typeof(Models.ActionRequest).GetProperty(key);
Type t = propertyInfo.PropertyType; // t will be System.String
if (t.Name == "Int32")
{
actionRequestType.GetProperty(key).SetValue(systemActivatorObject, Convert.ToInt32(formCollection[key]), null);
}
else
{
actionRequestType.GetProperty(key).SetValue(systemActivatorObject, formCollection[key], null);
}
}
return (Models.ActionRequest)systemActivatorObject;
}
catch (Exception ex)
{
throw ex;
}
}
}
I would like to know if there can be any improvements made to this, or recommendations of how else to accomplish this in an efficient manner.
Thanks.
ASP.Net MVC already does all of this for you.
Just add a Models.ActionRequest actionRequest parameter to your action.
If you want to add additional validation logic, use System.ComponentModel.DataAnnotations.
Simply use the default model binder which will take care of instantiating and binding the ActionRequest from the request parameters:
public class NewsfeedAppPoolController : Controller
{
[ActionName("EnableAppPool"), AcceptVerbs(HttpVerbs.Post)]
[ValidateInput(false)]
[NoCache]
public ActionResult EnableAppPool(ActionRequest actionRequest)
{
// do things with actionRequest
return null;
}
}
The appropriate pattern is,
[HttpPost]
public ActionResult Save(Employee employee)
{
if(ModelState.IsValid)
{
db.Save(employee);
RedirectToAction("Index");
}
return View();
}
Notes:
The employee instance is automatically created and populated by the default model binder from the values available in the request(form, querystrings, routedata and more)
When the default model binder binds the values to the model it also does the validation and store all the errors in the ModelState dictionary, so by checking the ModelState.IsValid you can know that whether the validation is succeeded or not.
To know more about model binding refer this.
To know more about model validation refer this.

How to return HTTP status code form Custom Model Binder

I have a custom model binder which pulls an implementation of an interface from a MEF container. It is implemented as follows:
public class PetViewModelBinder : DefaultModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var petId = bindingContext.ValueProvider.GetValue("id");
var container = controllerContext.HttpContext.Application[MvcApplication.PLUGINS] as CompositionContainer;
Lazy<IPet, IPetMetadata> pet = null;
try
{
pet = container.GetExport(typeof(IPet), petId);
var petVM = new Models.PetViewModel(pet);
bindingContext.ModelMetadata.Model = petVM;
return base.BindModel(controllerContext, bindingContext);
}
catch (Exception)
{
throw;
}
finally
{
container.ReleaseExport(pet);
}
}
This works splendidly when MEF has an Export of petId... but returns http status 500 (server error) when an Export does not exist. Error message obfuscation requirements dictate http status 403 (forbidden) should be returned.
What can be done to trap the error, change the response status, and either not return content, or re-route the Action to handle this condition?
If you want to return a particular http status code you should do that from a controller or action filter.
One way to do this is to return null from your model binder and handle that in your controller. This is a bit coarse however so you won't be able to distinguish between different errors.
Another way to do it would be to throw a specific exception and handle that in your (global) error handling. A customized HandleError action filter could do this:
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public int StatusCode { get; set; }
public override void OnException( ExceptionContext filterContext )
{
base.OnException( filterContext );
if ( StatusCode > 0 )
{
filterContext.HttpContext.Response.StatusCode = StatusCode;
}
}
}
In your controller, decorate the action with this attribute:
[CustomHandleError( ExceptionType = typeof (NotAllowedException), View = "~/Views/Shared/Error.cshtml",
StatusCode = 403 )]
public ActionResult Index( FancyModel model )
{
return View( model );
}
Finally, in your model binder throw a NotAllowedException, which is a custom exception type you'll also need to define.
Note that this will only work on your development setup if you have enabled custom errors in your web.config file.

Resources