FormUrlEncodedMediaTypeFormatter vs JQueryMvcFormUrlEncodedFormatter - asp.net-web-api

I have created a default web api project with at least those 2 media formatters loaded. Both are for the same content-type:
FormUrlEncodedMediaTypeFormatter: application/x-www-form-urlencoded
JQueryMvcFormUrlEncodedFormatter: application/x-www-form-urlencoded
When I do a simple http post form with enctype="application/x-www-form-urlencoded" it works only with the JQueryMvcFormUrlEncodedFormatter, that means my sent complex object is not null at server side.
When I remove the formatter JQueryMvcFormUrlEncodedFormatter at application startup and do the simple http post form again I expect it to work again but it does not.
I get an exception that no appropriate formatter is loaded.
Thats not true -actually-
Why does it not work?
P.S.
I found that this is the difference:
– System.Net.Http.Formatting.FormUrlEncodedMediaTypeFormatter, for handling HTML form URL-encoded data
– System.Web.Http.ModelBinding.JQueryMvcFormUrlEncodedFormatter, for handling model-bound HTML form URL-encoded data
but I do not understand the difference!
I do not even use jquery to post my form:
<form role="form" method="post" action="api/values" enctype="application/x-www-form-urlencoded">
<input type="text" class="form-control" name="firstName" placeholder="Enter first name">
<input type="text" class="form-control" name="lastName" placeholder="Enter last name">
<button type="submit" class="btn btn-default">Submit</button>
</form>

FormUrlEncodedMediaTypeFormatter binds application/x-www-form-urlencoded body to FormDataCollection type, and only that type.
JQueryMvcFormUrlEncodedFormatter however uses available ModelBinders to first parse the body to FormDataCollection and then use the first compatible ModelBinder to parse that into the final model. It's like mixing Model Binding approach and Media Type Formatting approach, which AFAIK is not explained anywhere in the WebAPI docs.
Both formatters are registered by default. This is what I inferred reading WebAPI source code.

There are 4 out of box formatters
JsonMediaTypeFormatter
XMLMediaTypeFormatter
FormUrlEncodedMediaTypeFormatter
JQueryMvcFormUrlEncodedFormatter
The first two media type formatters can serialize and deserialize CLR types to request/response and vice versa. But 3rd one neither serializes nor deserializes to/from any CLR type. 4th formatter can deserialize incoming raw data to CLR type.
Hence in your case, you are experiencing with error after you remove JQueryMvcFormUrlEncodedFormatter since 3rd formatter could not able to deserialize incoming request data to CLR type.

Related

Opayo (SagePay) Amex payments fail since 3DSv2 (Using Direct V4)

Is anybody else having issues taking Amex payments with Opayo (SagePay) Direct protocol V4 since the 6th July?
Everything was fine before then, seems to be related to 3DSv2 but I'm successfully using the V4 protocol and taking 3DSv2 payments against Visa/Mastercard.
I get all the way through the transaction including successfully completing the 3DSv2/Safekey pages and then when I pass the CRes back to Opayo I get a "5086 : Unexpected CRes" response
When I base64 decode the CRes I get the below. (trimmed to remove full ID's)
{"threeDSServerTransID":"5bfe447a-5443-...","acsTransID":"00f9a54d-84f0-...","messageType":"CRes","messageVersion":"2.1.0","transStatus":"N"}
The data I send to SafeKey looks like the below (form auto submits with JS) threeDSSessionData is the VPSTxID base64 encoded including the {} brackets
<form name="form" action="https://acs-safekey.americanexpress.com/GravityACS/processing3ds" method="POST">
<input type="hidden" name="TermUrl" value="https://...?action=return3d&VendorTxCode=XXX">
<input type="hidden" name="creq" value="ewog...ICIwMiIKfQ">
<input type="hidden" name="threeDSSessionData" value="ezg1NTA5MzM.......UU1OH0=">
<input class="button" type="submit" value="Continue">
</form>
The transStatus:N response makes me wonder if its something on the way to SafeKey and Opayo aren't handling the decline? i.e. is it because I'm doing the following and hence they are declining the transaction - but then wouldn't it do that before it got to 3DS?
COFUsage=FIRST&InitiatedType=CIT&MITType=UNSCHEDULED
Thanks
Dave

spring form input fields type attribute

I am converting some plain HTML to using spring form tags.Although it looks like
spring form input does not have the attribute type. I was able to successfully
pass a hidden variable as follows:
<form:input type="hidden" name="displayId" id="displayIdentifier" path="displayIdentifier" value="${value1}"/>
Earlier the plain HTML was as follows:
<input type="hidden" name="displayId" id="displayIdentifier" value="${value1}"/>
I looked online and saw that the for:input does not have the type attribute, yet it seems to be working correctly.
The input tag is declared with
<dynamic-attributes>true</dynamic-attributes>
That allows passing dynamic attributes, not explicitely declared in the tag. The tag simply stores their name and value and writes them as is on the generated HTML input. That allows adding a type, or a data attribute, or any attribute you want to the tag.
See http://docs.oracle.com/javaee/6/api/javax/servlet/jsp/tagext/DynamicAttributes.html for more information.

How to PATCH or DELETE from a form without javascript

I am writing a simple crud app on Phoenix. How does one submit PATCH and DELETE requests from a form without using javascript?
Ah I figured it out, same as rails:
<form method="POST">
<input name="_method" type="hidden" value="patch" />
...
Handled in Plug.MethodOverride: https://github.com/elixir-lang/plug/blob/master/lib/plug/method_override.ex
<form> elements only support sending GET and POST requests. The workaround that Rails uses is to read the request method from the _method request parameter, overriding the actual request method (the GET or POST method).
Phoenix does exactly the same through Plug, the Rack-like framework that Phoenix is built on. Long story short, Plug provides middlewares and one of the middlewares it provides is Plug.MethodOverride, which does exactly what we discussed. Doing so in a middleware, the Phoenix app barely knows that the original request was not a GET/POST.
You can see Plug.MethodOverride used in Phoenix's source code.
As the others have mentioned, Phoenix handles this in the routing via the MethodOverride plug.
In order to change this in the template with the form_for helper, use the :method parameter:
<%= form_for #changeset, path(#conn, :update), [multipart: true, method: "patch"], fn f -> %>
This will add the hidden input to the HTML, as noted by #greggreg:
<input name="_method" type="hidden" value="patch" />

Freemarker Checkboxes input in Spring form

I have an HTML form bound to a Spring model to take in user data and add it to a database. This works fine. I have used Spring Freemarker macros for the fields to take input and validate before sending, e.g.
<#spring.formInput path="myForm.username"/>
<#spring.showErrors ", "/>
This also works fine for text input. What is causing me problems is rendering multiple checkboxes with the Spring macro. My original HTML was:
<input name="roleList" type="checkbox" value="1"/>Adminstrator
<input name="roleList" type="checkbox" value="2"/>Developer
<input name="roleList" type="checkbox" value="3"/>Customer
I created a Java Map<String, String> of this information with the keys as "1", "2", "3" in my controller method and added it to the model, then replaced the HTML with this macro in my ftl template:
<#spring.formCheckboxes path="quickForm.roleList" options="${roleMap}" separator="<br>"/>
But I get an error
Expecting a string, date or number here, Expression roleMap is instead a freemarker.template.SimpleHash
Why would it give that message if it requires a Map? (as in the Spring Docs for FreeMarker macros) Can anyone explain how I should be providing the checkbox data?
Finally worked this out, so for anyone who's interested: it wasn't as straightforward as just creating a HashMap of values and adding them with model.addAttribute("roleMap", myHash) - I had to create a service class to do this instead: it retrieved my list of roles from a database table and then converted them into a HashMap<String, String>. I then called this in my controller method, added it to my model (called "roleMap" here) and used it within my FreeMarker template without the usual formatting, like this:
<#spring.formCheckboxes path="quickForm.roleList" options=roleMap separator="<br>"/>
Having the data converted in a service method was key for Spring to use it as checkbox options.

How to test CAS with jmeter?

request:
I send a "get" http request, has no parameters;
path: http://192.168.22.139:8080/KSP
response:
<input id="username" type="text" name="username" required/>
<input id="password" type="password" name="password" required/>
<input type="hidden" name="lt" value="LT-697-vbNmm6NKOZ0cd7Wg1ywzbMKLa0DnOc" />
<input type="hidden" name="execution" value="e1s1" />
<input type="hidden" name="_eventId" value="submit" />
And I add two XPath Extractor to get lt and execution:
reference name: lt;
xPath query: //*[#id="login"]/input[3]
reference name: execution;
xPath query: //*[#id="login"]/input[4]
Then I send another request with username/password/service/It/execution/_eventId:
Error: ticket and execution I get is empty, I get the xpath by chrome, so what is the problem?
From the first response, can use Regular Expression Extractor to extract ticke and lt.
Then send the second request with parameter:
username/password/It/execution/_eventId/_eventId
By the way, you should add HTTP Cookie Manager,
I didnot see parameters of your first request. At least I didnot see the lt.
The second request should be a GET request, and the parameters are: service and ticket(This is not jsessionid, the value is generated by CAS, and it is the same with the parameter lt in the first request to the CAS login ).
There is a few things you need to change in the second request:
add execution parameter (extract it from the first request, eg. with XPath Extractor or Regular Expression Extractor),
the XPath expression would be something like .//*[#id='fm1']//*[#name='execution']/#value
add _eventId=submit parameter,
the lt parameter (the login ticket) should be extracted from the login form, too - it changes each time; see XPath Extractor or Regular Expression Extractor,
XPath expression: .//*[#id='fm1']//*[#name='lt']/#value,
not required, but will look nicer - change GET to POST.
If you're testing CAS login itself I can suggest using JMeter HTTP Proxy server to record login process, catch all values which are being passed, detect those, which are dynamic and deal with them via Regular Expression Extractor, XPath, Beanshell, etc. Post Processors - what you're most comfortable with.
In case if your application is behind CAS I guess that CAS login simply adds a cookie and your application considers user authenticated basing on it. In this case you can simply store cookies somewhere in CSV file and use them via HTTP Cookie Manager to simulate authenticated users.

Resources