Passing an object as parameter to Breeze controller action - asp.net-web-api

I'm trying to send an object as a parameter through Breeze without success.
Using the following code I can send a primitive type:
Client:
var query = EntityQuery
.from('account/authenticate')
.withParameters({ loginRequest: "hello" });
Server:
[BreezeController]
public class AccountController : ApiController
{
[HttpGet]
public LoginResult Authenticate(string loginRequest)
{
// String for loginRequest received successfully
}
}
However, if I try and pass a complex type up, the param is always null:
Client:
var loginRequest = { userName: 'me', password: 'pass' };
var query = EntityQuery
.from('account/authenticate')
.withParameters({ loginRequest: loginRequest });
Server:
[BreezeController]
public class AccountController : ApiController
{
[HttpGet]
public LoginResult Authenticate(LoginRequest loginRequest)
{
// Object for loginRequest always null
}
}
I believe this is in part because Breeze always uses a GET for queries. A POST might handle the serialization correctly, but I can't see any way in the Breeze API to force a POST.
If I pass up a JSON string representation of the object I can pick it up server-side, but this requires manual deserialization. I realise I could do this outside of Breeze with a standard WebAPI call, but I'm trying to keep all of my server-side calls running through the same pipeline.
Is it possible to do this?

You may be missing a [FromUri] attribute. Any time I tried to pass a more complex object or set of parameters everything would come back as null until I added that attribute.
[BreezeController]
public class AccountController : ApiController
{
[HttpGet]
public LoginResult Authenticate([FromUri] LoginRequest loginRequest)
{
// Object for loginRequest always null
}
}

Why not use ->
var loginRequest = { userName: 'me', password: 'pass' };
var query = EntityQuery
.from('account/authenticate')
.withParameters( loginRequest);
instead of
var loginRequest = { userName: 'me', password: 'pass' };
var query = EntityQuery
.from('account/authenticate')
.withParameters({ loginRequest: loginRequest });

Related

How to send JSON response from controller?

I want to pass a boolean value from my controller to javascript using json but couldnot find a way as I am new to spring mvc.
While using servlet we wrote:
response.getWriter().println(somevalue)
and the somevalue can be received using ajax.
Here my controller method is:
#RequestMapping(value = REGISTERACTION , method = RequestMethod.POST)
#ResponseBody
public boolean RegisterUser(#ModelAttribute("register") Register register,HttpServletRequest request, HttpServletResponse response)
{
boolean Registrationsuccess = userService.RegisterUser(register);
return Registrationsuccess;
}
So, here the boolean variable is Registrationsuccess which I want to send to js file and receive it using ajax.
And in my javascipt function which is called using onsubmit event-->
function AccountExists()
{
$.ajax({
type: 'POST',
url: 'registerProcess',
success: function(data){
let detail = JSON.parse(data);
if( data == true)
alert("Success");
else
alert("Not ");
}
});
}
Getting error --
The target resource does not have a current representation that would be acceptable to the user agent, according to the proactive negotiation header fields received in the request, and the server is unwilling to supply a default representation.
You need to use ResponseEntity and #RestController for JSON Response.
Note : #RestController includes both annotations #Controller and #ResponseBody.
Try with this :
#RestController
#RequestMapping("controller")
public class Controller {
#PostMapping("REGISTERACTION")
public ResponseEntity<Boolean> RegisterUser(#ModelAttribute("register") Register register)
{
Boolean registrationSuccess = userService.RegisterUser(register);
return new ResponseEntity<Boolean>(registrationSuccess , HttpStatus.OK);
}
}
Try to use #ResponseBody annotation in your controller's method. And change the return type of the method to Boolean, then return Registrationsuccess instead of ModelAndView.
You can achieve this using 2 approach
Approach 1: Set model attribute and using expression language you can find on jsp
model.addAttribute("test",true);
in Jsp page
${test}
Approach 2: If you are sending ajax request instead of ModelAndView create a object
set any attribute boolean and return object from method #ResponseBody annotation you will get json in Ajax Response
#RequestMapping(value = REGISTERACTION , method = RequestMethod.POST)
public #ResponseBody MyCustomObject RegisterUser(#ModelAttribute("register") Register register,HttpServletRequest request, HttpServletResponse response)
{
boolean Registrationsuccess = userService.RegisterUser(register);
MyCustomObject cusobj=new MyCustomObject();
cusobj.setStatus(true);
return cusobj;
}
Whatever code you have written it will not return json(It is basically form submission approach) so you have to go with first approach.

Spring MVC, validate if request has duplicate params

We have multipart post request mapped to below method.
fun post(#RequestParam(value = "photo", required = true) photo: Array<MultipartFile>,
#Valid person: Person)
class Person {
int id,
String name
}
In the below example has more than one name param in the request
localhost:8080/api
post body:
id:101
name: Jhon
name: Jhonny
Is there a way to reject the request if it contains repeated params?
You could add a HttpServletRequest to the handler method argument list, validate it, and return a ReponseEntity.badRequest().build() if there are multiple occurrences of the same parameters.
#GetMapping
public ResponseEntity handlerMethod(HttpServletRequest request) {
if (request.getParameterValues("name").length > 1) {
return ResponseEntity.badRequest().build();
}
return ResponseEntity.ok().build();
}
If you want to do it across the whole application you can define a filter:
#Component
class DuplicateRequestParameterFilter extends OncePerRequestFilter {
Enumeration<String> parameters = request.getHeaderNames();
while (parameters.hasMoreElements()) {
if (request.getParameterValues(parameters.nextElement()).length > 1) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
}
filterChain.doFilter(request, response);
}
no,there would be a array named 'name' or a string which contain two name,it is looked like this
{id:101,name:'Jhon,Jhonny'} or {id:101,name:['Jhon','Jhonny']}
which is determined by how to receive it
if name is a string ,the result would be 'Jhon,Jhonny'.
if name is a string array ,the result would by ['Jhon','Jhonny'].

Spring MVC Ajax form properties name

I have a form with a list of fields:
type, name, description, height ,width
I send by ajax to my controller, my controller receive this ajax call but he said that all input fields are null.
My mapped DTO have the same fields but with distinct name, really I don't need use the same name in my call ajax that in my #RequestBody dto class.
Its possible? I am limited to use same names in the class and the ajax calls?
This aren't a problem really, but I can't found any info about this.
My DTO properties:
ResourceCreateDTO [resourceTypeId=null, resourceId=null,
resourceName=null, resourceDescription=null, folderId=null]
My JSON data:
resource-description: "asdfasdfasdfasdfsadfasdfsdfasdfasdfasdfasdfsadfasdfasdf"
resource-folder: "0"
resource-folder-type: "1000"
resource-id: "1006"
resource-name: "asdfasdfasdfasdf"
My AJAX Call:
$("#createModalSubmit").click(function(){
var data = {};
$('#createForm *').filter(':input').each(function(){
var input = $(this);
data[input.attr("name")] = input.val();
delete data["undefined"];
});
$.ajax({
contentType : "application/json; charset=utf-8",
type: "POST",
url: context + "/editor/create",
data: JSON.stringify(data),
dataType : 'json',
cache: false,
success:function(result){
},
error:function(){
}
});
});
My Controller config:
#RequestMapping(value = "/editor/create", method = RequestMethod.POST)
public #ResponseBody ResourceDTO create(#RequestBody ResourceCreateDTO dto)
throws Exception {
System.out.println("dto: " + dto.toString());
This system out prints the above DTO toString.
I am searching any type of anotation or config that I can name the DTO properties:
#MyCustomName("resource-name")
private String resourceName;
Use my "resource-name" from the AJAX call.
If your DTO cannot have the same name that is being used in your ajax, you can then match it manually inside your controller.
#RequestMapping(value = "/editor/create", method = RequestMethod.POST)
public #ResponseBody ResourceDTO create(#RequestBody String dto)
throws Exception {
//mapping
}
Or
#RequestMapping(value = "/editor/create", method = RequestMethod.POST)
public #ResponseBody ResourceDTO create(#RequestBody Map<String,Object> dto)
throws Exception {
//mapping
}

Web Api 2: Authorising against custom claims

In certain controllers, I want to authorize a user against a company ID.
For example, consider the following resource:
api/v1/companies/1234/orders
This should only be accessible by users who belong to company 1234.
Note that I am using OAuth token bearer authentication.
Creating the company claim in OAuthAuthorizationServerProvider:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//...
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
// Creating the companyId claim
identity.AddClaim(new Claim("CompanyId", user.CompanyId.ToString()));
context.Validated(identity);
}
The current controller implementation for the orders resource:
[RoutePrefix("api/v1/companies/{companyId:Guid}/orders")]
public class OrdersController : ApiController
{
[Route]
public IHttpActionResult GetOrders(Guid companyId)
{
var orders = OrdersRepository.Get(companyId);
return Ok(orders.Select(x => OrderModel.From(x)));
}
}
Where do I authorize the companyId URL value against the identity claim?
Can [Authorize] be somehow used here?
Here is a custom authorize filter you could use
using System.Net.Http;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
public class AuthorizeAction : AuthorizeAttribute {
public string CompanyId;
protected override bool IsAuthorized(HttpActionContext actionContext) {
if (String.IsNullOrEmpty(CompanyId))
{
var routeData = actionContext.Request.GetRouteData();
var myId = routeData.Values["CompanyId"] as string;
CompanyId = myId;
}
var user = actionContext.RequestContext.Principal as ClaimsPrincipal;
if (user == null || !user.Identity.IsAuthenticated)
return false;
if (user.Claims.Any(claim => claim.Type.Equals("CompanyId") && claim.Value.Equals(CompanyId)))
return true;
return false;
}
}
You could also decorate your action or controller with below if you wanted only a single company to access a action or controller.
[AuthorizeAction(CompanyId = "1234")]
See the approach in https://github.com/AzureADSamples/NativeClient-DotNet/blob/master/TodoListService/Controllers/TodoListController.cs - instead of "scope" you can use your custom claim type

How to get HttpRequestMessage instead of HttpContext.Current in WebApi

I have found several sources that say that you should not use HttpContext.Current in WebApi but none that say how you should handle those cases where we used to use HttpContext.Current.
For example, I have a LinkProvider class that creates links for an object. (simplified to stay on topic).
public abstract class LinkProvider<T> : ILinkProvider<T>
{
protected ILink CreateLink(string linkRelation, string routeName, RouteValueDictionary routeValues)
{
var context = System.Web.HttpContext.Current.Request.RequestContext;
var urlHelper = new System.Web.Mvc.UrlHelper(context);
var url = string.Format("{0}{1}", context.HttpContext.Request.Url.GetLeftPart(UriPartial.Authority), urlHelper.RouteUrl(routeName, routeValues));
///...
return new Link(linkRelation, url);
}
}
and this class is used by a MediaTypeFormatter.
This class is expected to build a link using the same host that came from the original request and leveraging any route values that were on the original request.
But... how do I get a hold of the HttpRequestMessage? This will be encapsulated by a MediaTypeFormatter - but it doesn't have one either.
There must be an easy way to get hold of the HttpRequestMessage - what am I overlooking?
thanks
Jon
I ended up creating the following base Formatter which exposes the request, now I will be able to pass it along to the LinkProvider.
public class JsonMediaTypeFormatterBase : JsonMediaTypeFormatter
{
public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, System.Net.Http.HttpRequestMessage request, MediaTypeHeaderValue mediaType)
{
Request = request;
return base.GetPerRequestFormatterInstance(type, request, mediaType);
}
protected HttpRequestMessage Request
{
get;
set;
}
}

Resources