Recognizing parameters and mapping to complex object - asp.net

public class MyClass
{
public string empty;
public int number;
public AnotherClass Another;
}
public calss AnotherClass
{
int number1;
int number2;
}
method
[HttpGet]
[Route("check")]
public HttpResponseMessage Get([FromBody] MyClass request)
{
//
return new HttpResponseMessage() { StatusCode = HttpStatusCode.OK};
}
Is it possible to map request where user send all parameters in body like this
{
"empty":"test",
"number":"5",
"number1":"10",
"number2":"15"
}
I don't want to change JSON part.

Related

RestController JSON Response object format

I am using Spring Boot to return data from a Repository. I would like to format my JSON so that it plays nicely with ExtJS' ajax handling. Essentially I would like to include properties to handle success/failure, count, and errorMsg along with a List of data from the repository.
I have tried by creating a ResponseDTO object that I'm returning from my Rest Controller.
#RestController
public class AdminController {
private static final Logger logger = LogManager.getLogger(AdminController.class);
#Autowired
private UserService userService;
#Autowired
private SecurityService securityService;
#Autowired
private UserValidator userValidator;
#GetMapping("/searchUsers")
public ResponseDTO searchUsers(String name, String active) {
int activeFlag;
List<User> users;
ResponseDTO resp;
if(active.equals("true")) {
activeFlag = 1;
} else activeFlag=0;
if(StringUtils.isEmpty(name)) {
users= userService.findAllUsers(activeFlag);
} else {
users= userService.findByUsernameActive(name, activeFlag);
}
return new ResponseDTO(users, true);
}
}
Here's my DTO that I use in the controller:
public class ResponseDTO {
private boolean success;
private int count = 0;
private List<?> values;
public boolean getSuccess() {
return this.success;
}
public void setState(boolean st) {
this.success=st;
}
public int getCount() {
return this.count;
}
public void setCount(int cnt) {
this.count=cnt;
}
public List<?>getValues() {
return this.values;
}
public void setValues(List<?> vals) {
this.values = vals;
}
public ResponseDTO(List<?> items, boolean state) {
this.success = state;
values = items;
this.count = items.size();
}
}
Here's what the JSON I get back looks like:
{
"ResponseDTO": {
"success":true,
"count":2,
"values":[{obj1 } , { obj2}]
}
}
what I would like to get is something more like:
{
"success" : true,
"count" : 2,
"values" [{obj1},{obj2}]
}
I'm using Spring Boot and Jackson annotations. I have used an annotation to ignore individual fields in the objects in the results array, but I can't find a way to unwrap the ResponseDTO object to not include the class name.
When you serialize ResponseDTO POJO, you should not get 'ResponseDTO' in the response by default. Because, the root wrap feature is disabled by default. See the doc here. If you have the below code, please remove it.
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);

In ASP.Net Core MVC, what's "value" used for in ControllerBase.StatusCode()?

It's the second param. I don't see any documentation describing what happens when I return a StatusCode ObjectResult that has that param set.
//
// Summary:
// Creates a Microsoft.AspNetCore.Mvc.ObjectResult object by specifying a statusCode
// and value
//
// Parameters:
// statusCode:
// The status code to set on the response.
//
// value:
// The value to set on the Microsoft.AspNetCore.Mvc.ObjectResult.
//
// Returns:
// The created Microsoft.AspNetCore.Mvc.ObjectResult object for the response.
[NonAction]
public virtual ObjectResult StatusCode(int statusCode, object value);
The value will be the payload/body included in the response, formatted by the applicable media formatter.
For the code below and when using the application/json content-type, this will be
{ "a" : "foo", "b" : 1 }
public class Dto
{
public string A { get; set; }
public int B { get; set; }
}
public class MyController : Controller
{
[HttpGet]
public IActionResult MyAction()
{
var dto = new Dto { A = "foo", B = 1};
return StatusCode(200, dto);
}
}

Data Annotations to sanitize request and response before logging

I'm looking for a reliable solution to log details of requests and responses made to and from our controllers. However, some of the data passing through contains sensitive information that should not be written to a log.
In the controller, the inbound request is bound to a single model from the request body, and as the request is answered, a single model is passed to the Ok() result like this (very simplified):
[HttpGet]
[Route("Some/Route")]
public IHttpActionResult SomeController([FromBody] RequestType requestObj)
{
ResponseType responseObj = GetResponse(requestObj)
return this.Ok(responseObj);
}
Now my goal is to somehow log the contents of the request and response object at the beginning and end of the controller, respectively. What I would like to do is bind the models first, then log out their attributes. An example of the RequestType is something like:
public class RequestType
{
public string SomeAttribute { get; set; }
public string AnotherAttribute { get; set; }
public string Password{ get; set; }
}
And the log would look something like:
[date-time] Request to SomeController:
SomeAttribute: "value_from_request"
AnotherAttribute: "another_value"
Password: "supersecret123"
Now clearly we don't want the password to be logged. So I would like to create a custom data annotation that would not log certain fields. Its use would look like this (updated RequestType):
public class RequestType
{
public string SomeAttribute { get; set; }
public string AnotherAttribute { get; set; }
[SensitiveData]
public string Password{ get; set; }
}
Where would I start with this? I'm not incredibly familliar with .NET, but know that there are many sort of magic classes that can be subclassed to override some of their functionality. Is there any such class that can help here? Even better, is there any way to do this during the model binding? So we could catch errors that occur during model binding as well?
We should be able to achieve what you're looking for with an ActionFilterAttribute.
Capture Requests Attribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class CaptureRequestsAttribute : ActionFilterAttribute // *IMPORTANT* This is in the System.Web.Http.Filters namespace, not System.Web.Mvc
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var messages = actionContext.ActionArguments.Select(arg => GetLogMessage(arg.Value));
var logMessage = $"[{DateTime.Now}] Request to " +
$"{actionContext.ControllerContext.Controller}]:\n{string.Join("\n", messages)}";
WriteToLog(logMessage);
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var result = actionExecutedContext.Response.Content as ObjectContent;
var message = GetLogMessage(result?.Value);
var logMessage = $"[{DateTime.Now}] Response from " +
$"{actionExecutedContext.ActionContext.ControllerContext.Controller}:\n{message}";
WriteToLog(logMessage);
base.OnActionExecuted(actionExecutedContext);
}
private static void WriteToLog(string message)
{
// todo: write you logging stuff here
}
private static string GetLogMessage(object objectToLog)
{
if (objectToLog == null)
{
return string.Empty;
}
var type = objectToLog.GetType();
var properties = type.GetProperties();
if (properties.Length == 0)
{
return $"{type}: {objectToLog}";
}
else
{
var nonSensitiveProperties = type
.GetProperties()
.Where(IsNotSensitiveData)
.Select(property => $"{property.Name}: {property.GetValue(objectToLog)}");
return string.Join("\n", nonSensitiveProperties);
}
}
private static bool IsNotSensitiveData(PropertyInfo property) =>
property.GetCustomAttributes<SensitiveDataAttribute>().Count() == 0;
}
Sensitive Data Attribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class SensitiveDataAttribute : Attribute
{
}
Then, you can just add it to your WebApi controller (or a specific method in it):
[CaptureRequests]
public class ValuesController : ApiController
{
// .. methods
}
And finally your models can just add the SensitiveDataAttribute:
public class TestModel
{
public string Username { get; set; }
[SensitiveData]
public string Password { get; set; }
}
This does not make use of DataAnnotations,however, One way that comes to mind would be to use the serialization. If your payload is within a reasonable size you could serialize and deserialize your RequestType class when reading and writing to/from a log. This would require a custom serialization format or making use of the default, xml.
[Seriliazeble()]
public class RequestType
{
public string SomeAttribute { get; set; }
public string AnotherAttribute { get; set; }
[NonSerialized()]
public string Password{ get; set; }
}
Using the above attribute will omit Password from serialization. Then you copuld proceed to Logger.Log(MySerializer.Serialize(MyRequest)); and your sensitive data will be omitted.
This link describes the approach in detail.
For xml serialization, simply use the XmlSerializer class.
public class MySerializationService
{
public string SerializeObject(object item)
{
XmlSerializer serializer = new XmlSerializer(item.GetType());
System.IO.MemoryStream aMemStr = new System.IO.MemoryStream();
System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(aMemStr, null);
serializer.Serialize(writer, item);
string strXml = System.Text.Encoding.UTF8.GetString(aMemStr.ToArray());
return strXml;
}
public object DeSerializeObject(Type objectType, string objectString)
{
object obj = null;
XmlSerializer xs = new XmlSerializer(objectType);
obj = xs.Deserialize(new StringReader(objectString));
return obj;
}
}
Then using the above or similar methods you can read and write in a custom format.
Write :
string logData=new MySerializationService().SerializeObject(myRequest);
Read :
RequestType loggedRequest= (RequestType)new MySerializationService().DeSerializeObject(new RequestType().GetType(), logData);

How to parse json data into different object dynamically by using Jackson in Spring3 MVC project

I want to know if there is a way to parse json data dynamically into different object by using jackson feature in Spring3.
I have a parent class as below:
public class Recording {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
And two children:
public class Child1Recording extends Recording {
private String program;
public String getProgram() {
return program;
}
public void setProgram(String program) {
this.program = program;
}
}
public class Child2Recording extends Recording {
private String time;
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
Controller like this:
#RequestMapping(value = "/init/postCheck.ajax", method = RequestMethod.POST)
public #ResponseBody
String postCheck(#RequestBody Recording recording) {
if (recording instanceof Child2Recording) {
return "\"child2 success\"";
} else if (recording instanceof Child1ecording) {
return "\"child1 success\"";
}
return "\"only parent Recording\"";
}
i have different scenarios to post different json data to the backend, i am wondering if there is a way to make controller works like i said above?
For now, if i send a Child2Recording data, an error occurs when parsing it. I can't get the correct object that i expect.

ASMX WebService returning XmlNode instead of custom object

Here is the webservice:
Custom classes:
public class A
{
public A()
{
}
public B prop { get; set; }
}
public class B
{
public B()
{
}
public A prop { get; set; }
}
Webmethod:
[WebMethod]
[XmlInclude(typeof(A))]
public object Test()
{
A a = new A();
a.prop = new B();
return a;
}
Here is the client side:
Service ws = new Service();
var response = ws.Test();
So, why is the webservice returning XmlNode list instead of class A? How to solve it?
PS: if I comment public A prop { get; set; } line, it works
Ok, found the solution:
I could use a wrapper, like this:
C#.NET WebService returning object
Or I use the [return:] attribute, like this:
[WebMethod]
[return: XmlElement(typeof(A))]
public object Test()
{
A a = new A();
a.prop = new B();
return a;
}
http://social.msdn.microsoft.com/forums/en-US/asmxandxml/thread/599ed74a-ad3d-451e-9a41-551900c542da/
About attribute targets:
http://msdn.microsoft.com/en-us/library/b3787ac0(v=vs.80).aspx

Resources