Remove json field in ASP MVC WebApi Action Method - asp.net

I have a controller that accepts a model UpdateProductCommand like this:
public IHttpActionResult UpdateProduct(UpdateProductCommand command)
{
command.AuditUserName = this.RequestContext.Principal.Identity.Name;
// ....
}
For security issues, the AuditUserName field should never be set outside (from the API call).
How can I remove (or truncate) the value of this field from JSON request?

It can be achieved by a following ModelBinder:
using Newtonsoft.Json.Linq;
public class FieldRemoverModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
string content = actionContext.Request.Content.ReadAsStringAsync().Result;
JObject json = JObject.Parse(content);
JToken property = json.GetValue(bindingContext.ModelName, StringComparison.OrdinalIgnoreCase);
property?.Parent.Remove();
bindingContext.Model = json.ToObject(bindingContext.ModelType);
return true;
}
}
Use it like this:
public IHttpActionResult UpdateProduct(([ModelBinder(typeof(FieldRemoverModelBinder), Name = nameof(UpdateProductCommand.AuditUserName))]UpdateProductCommand command)
{
// here command.AuditUserName will always be empty, no matter what's in json

That's what DTOs are for.
You can just create another class (UpdateProductCommandDto for example) that has only the properties you need / want to be used as the input, and then you can just use something like Automapper to map it to a new instance of UpdateProductCommand.

Related

How to pass a generic collection Class object as an argument

I've RESTful service Spring MVC based.
The service has a RESTful resource method that returns the following response:
public class OperationalDataResponse<T> {
private String status;
private String statusMessage;
private T result;
//getters and setters
}
This response object encapsulates the result object of type T.
On the client side I use RestTemplate with GsonHttpMessageConverter added.
I get the response from service as a ResponseEntity
I handle the generic response with runtime Type as below:
public class OperationalDataRestClient<REQ,RESULT_TYPE> {
public OperationalDataResponse<RESULT_TYPE> getOperationalData(String resourcePath, Map<String, Object> urlVariables, Class<RESULT_TYPE> resultType) {
//code to invoke service and get data goes here
String responseString = responseEntity.getBody();
response = GsonHelper.getInstance().fromJson(responseString, getType(OperationalDataResponse.class, resultType));
}
Type getType(final Class<?> rawClass, final Class<?> parameter) {
return new ParameterizedType() {
#Override
public Type[] getActualTypeArguments() {
return new Type[] { parameter };
}
#Override
public Type getRawType() {
return rawClass;
}
#Override
public Type getOwnerType() {
return null;
}
};
}
}
This works like a charm as long as my resultType is a non-collection class.
So, this works great from caller code:
getOperationalData(someResourcePath, someUrlVariables, MyNonGenericClass.class)
However if my resultType is a collection (say, List<String> or List<MyNonGenericClass>)
then I don't know how to pass the resultType Class from the caller code.
For example, from caller code,
getOperationalData(someResourcePath, someUrlVariables, List.class)
or
getOperationalData(someResourcePath, someUrlVariables, List<MyNonGenericClass>.class)
throws compilation error.
I tried passing on ArrayList.class as well but that too doesn't work.
Any suggestion how can I pass a generic collection as a resultType from caller code (in other words, as an example, how can I pass the class object of a List<String> or List<MyNonGenericClass> from caller code ?)
If you know that ResultType is coming as a List, Then it will obvious fail like you said compilation issue.Why? because you are trying to send a List when you method only accepts a single value.In order to over come that issue you will have to change the method arguments to the following
public OperationalDataResponse<RESULT_TYPE> getOperationalData(String resourcePath, Map<String, Object> urlVariables, List<Class<RESULT_TYPE>> resultType){
....
}
and you will have to make some slight modification to getType() Method,loop it and then pass each class value to getType method like so
for(MyNonGenericClass myClass:mylist){
getType(OperationalDataResponse.class, myClass.getClass());
}

ASP.NET. How to modify returned JSON (actionfilter)

We have an ASP.NET application. We cannot edit source code of controllers. But we can implement ActionFilter.
One of our controller action methods returns JSON. Is it possible to modify it in ActionFilter? We need to add one more property to a returned object.
Maybe, some other way to achieve it?
Found this interesting and as #Chris mentioned, though conceptually I knew this would work, I never tried this and hence thought of giving it a shot. I'm not sure whether this is an elegant/correct way of doing it, but this worked for me. (I'm trying to add Age property dynamically using ActionResult)
[PropertyInjector("Age", 12)]
public ActionResult Index()
{
return Json(new { Name = "Hello World" }, JsonRequestBehavior.AllowGet);
}
And the filter:
public class PropertyInjector : ActionFilterAttribute
{
string key;
object value;
public PropertyInjector(string key, object value)
{
this.key = key;
this.value = value;
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var jsonData = ((JsonResult)filterContext.Result).Data;
JObject data = JObject.FromObject(jsonData);
data.Add(this.key,JToken.FromObject(this.value));
filterContext.Result = new ContentResult { Content = data.ToString(), ContentType = "application/json" };
base.OnActionExecuted(filterContext);
}
}
Update
If it's not dynamic data which is to be injected, then remove filter constructor and hard code key & value directly and then the filter could be registered globally without editing the controller
GlobalFilters.Filters.Add(new PropertyInjector());

Get Action parameters from mvc

I'm trying to get the parameters of a request on exception and log them. How can I get action parameters from a request if the parameter is an object in asp.net mvc? I can only get the parameters if I send in the parameters like this:
public virtual ActionResult TestAction(string A,string B){
}
But not like this:
public virtual ActionResult TestAction(ObjectQuery query){
}
My code:
protected override void OnException(ExceptionContext filterContext)
{
string action = filterContext.RouteData.Values["action"].ToString();
string controller = filterContext.RouteData.Values["controller"].ToString();
string parameters = filterContext.HttpContext.Request.QueryString
}
EDIT:
QueryString returns empty:
You should use reflection to achieve this:
var parameters = MethodBase.GetCurrentMethod().GetParameters();
foreach (ParameterInfo param in parameters)
{
//do your logging here
}
I maybe over simplifying it, but you can get the parameters passed to the action using the Request.Form or Request.QueryString. The nice thing about them is they are of the type NameValueCollection which makes it easy to merge them together.
Then the exception is being thrown on the respective controller so you can get the method signature via reflection, albeit without the named parameter.
Using the simple code below properly gave the parameters passed to the action and doesn't care if it is a POST or GET operation.
protected override void OnException(ExceptionContext filterContext)
{
//Get all the info we need to define where the error occured and with what data
var param = new NameValueCollection {Request.Form, Request.QueryString};
var controller = filterContext.RouteData.Values["controller"].ToString();
var action = filterContext.RouteData.Values["action"].ToString();
var signature = filterContext.Controller.GetType().GetMethod(action).ToString();
//Let's write it to the stream in this case
Response.Write(string.Format("<h3>Controller: {0}</h3>", controller));
Response.Write(string.Format("<h3>Action: {0}</h3>", action));
Response.Write(string.Format("<h4>Signature: {0}</h4>", signature));
foreach (var key in param.AllKeys)
{
Response.Write(string.Format("<strong>Key:</strong> {0} = {1}<br />", key, param[key]));
}
Response.End();
}
There are some downsides I would imagine though. Collections will probably be represented in a very unfriendly way. Data which wasn't supposed to bind with the specific model will be shown as well.

Asp.Net Web Api - attribute for not binding/formatting a parameter?

I have a method on an ApiController that looks like this:
public IEnumerable<Items> GetSlideSets() {
IServiceClass serviceClass = new ServiceClass();
//...
Yes, I am aware that this is not good design but I'm addressing this issue in a different iteration.
At a certain point in my application I need to call this functionality from within the project itself so I thought I could simply reuse the controller (and why not, I can pluck it out of my IoC container). The only problem is that in this case, I need to inject my own implementation of IServiceClass, easy enough:
public IEnumerable<Items> GetSlideSets(IServiceClass serviceClass = null) {
serviceClass = serviceClass ?? new ServiceClass();
//...
Except now I am getting errors when calling this via a regular Api call Optionalparameter 'serviceClass' is not supported by FormatterParameterBinding.
I know that there are various attributes that control bindings. Is there one that I can put on the parameter to say it shouldn't bind.
Like others have mentioned, it's probably a better idea to inject the dependency in the constructor.
But if you really must avoid binding an action parameter, there isn't a built-in attribute but you can create one pretty easily. Here's what it could look like:
public class DontBindAttribute : ParameterBindingAttribute
{
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
return new DontBindParameterBinding(parameter);
}
private class DontBindParameterBinding : HttpParameterBinding
{
public DontBindParameterBinding(HttpParameterDescriptor parameter) : base(parameter)
{
}
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
{
actionContext.ActionArguments.Add(Descriptor.ParameterName, Descriptor.DefaultValue);
var completedTaskSource = new TaskCompletionSource<object>();
completedTaskSource.SetResult(null);
return completedTaskSource.Task;
}
}
}
You just need to apply the attribute to the parameter afterwards:
public IEnumerable<Items> GetSlideSets([DontBind] IServiceClass serviceClass = null)

Spring MVC controller custom parameter name

I have a Spring MVC controller. And I have in the method 50 parameters. All of the parameters have very specific name, for example: FOO[].
I don't want write 50 parameters in the method signature like this:
#RequestMapping(value = "/test", method = RequestMethod.POST)
#ResponseBody
public String test(
#RequestParam(value = "FOO[]") String foo,
#RequestParam(value = "BAR[]") String bar,
// Other 48 parameters
)
{
return "test";
}
I want to map all the parameters on the one object, I mean, I want to write a simple bean class with getter/setter and use it like method parameter.
But how can I set custom names to my class fields?
e.g.:
class FooBar {
#SomeAnnotation_for_binding_the_field_to_my_field_FOO[]
private String foo;
private String bar;
// Other 48 fields
// getters/setters
}
I know annotations are kinda cool, but think rationally. You HAVE to enumerate, in code, all the mappings. There is nothing implicit about mapping FOO[] to foo, it seems to be beyond your control. Just take the parameters as a map (you can always ask Spring to give you map of all parameters) and do something like:
#RequestMapping
public String test(#RequestParam Map<String, Object> map) {
MyObject mo = new MyObject();
mo.setFoo(map.get("FOO[]").toString());
mo.setBar(map.get("WOBBLE13[][]").toString);
return "whatever";
}
If you want to make this process more automatic, and if there exists an alorithm that maps parameter names to property names, you can use Spring's bean wrapper:
#RequestMapping
public String test(#RequestParam Map<String, String> map) {
BeanWrapper bw = new BeanWrapperImpl(new MyObject);
for (Entry<String, Object> entry : map.entrySet()) {
bw.setProperty(entry.getKey(), entry.getValue());
}
}
private static String decodeName(String n) {
return n.toLowerCase().substring(0,n.length() - 2);
}
You could make the process even more automatic by using a different Binder, you could (really, not a problem) add some custom annotations... but really, there is no point, if you just have a single case of 50 params. If you insist, add a comment.
THis sounds like a good time to use a hashmap, with key as the var name and value as value. Wrap that in a form backing object.
You could have a resource class i.e FooBarResource.jave and in your controller use that as a request body something like the following:
#ResponseBody
#RequestMapping(value = "/test", method = RequestMethod.POST)
#Secured({"ROLE_ADMIN"})
public ResponseEntity<ModelMap> createTest(#Valid #RequestBody FooBarResource body, UriComponentsBuilder builder) {

Resources