Asp.net core passing multiple parameter + web api - postman

I am submitting a form that passes three values to the controller, which are email, fullname and id fields.
#using (Html.BeginForm("SubmitResult", "TestAPI", FormMethod.Post, new { id = "postEmailForm" }))
{
<div id="details-container">
<input type="text" name="email" />
<input type="text" name="fullName" />
<input type="text" name="studentId" />
<button type="submit" id="send">Send</button>
</div>
}
Controller:
[HttpPost("SubmitResult/{email}/{fullName}/{studentId}")]
[Authorize(Roles = "Admin, Shop")]
public IActionResult SubmitResult(string email, string fullName, long? studentId)
{
}
However, when I click on submit button, it throws an error message in the console.
OPTIONS https://localhost:50138/TestAPI/SubmitResult
net::ERR_SSL_PROTOCOL_ERROR.
Headers:
Request URL: https://localhost:50138/TestAPI/SubmitResult
Referrer Policy: no-referrer-when-downgrade
How do I properly decorate the attribute in the controller, so I can pass multiple parameters to test API using Postman?
I was expecting something like below to work for testing.
http://localhost:50138/api/TestAPI/SubmitResult/test#gmail.com/MikeShawn/2

There are few issues with your code.
First issue is that it looks like when you post the data it tries to send it using a cross-origin request. If this is on purpose then you have to add CORS middleware in your pipe. If not - you have to figure out why it happens and fix it. There are not enough details in your question to say why it happens.
Two URLs have the same origin if they have identical schemes, hosts, and ports.
Second issue is that you are trying to send data by adding parameters to URL. This is wrong because the data will be sent in the request body. So regarding HttpPost attribute it should look like this:
[HttpPost]
[Authorize(Roles = "Admin, Shop")]
public IActionResult SubmitResult(string email, string fullName, long? studentId)
{
}
UPDATE
Just looked at your question again. It seems the page with form itself was opened using http scheme, but the POST request is actually going to https scheme. So to resolve first issue make sure that page with form is loaded using https scheme too.

Related

Flask - how to get query string parameters into the route parameters

Im very much new to Flask, and one of the starting requirements is that i need SEO friendly urls.
I have a route, say
#app.route('/sales/')
#app.route(/sales/<address>)
def get_sales(addr):
# do some magic here
# render template of sales
and a simple GET form that submits an address.
<form action={{ url_for('get_sales') }}>
<input type='text' name='address'>
<input type=submit>
</form>
On form submission, the request goes to /sales/?address=somevalue and not to the standard route. What options do I have to have that form submit to /sales/somevalue ?
I feel like I'm missing something very basic.
You would need to use JavaScript to achieve this so your template would become:
<input type='text' id='address'>
<button onclick="sendUrl();">submit</button>
<script>
function sendUrl(){
window.location.assign("/sales/"+document.getElementById("address").value);
}
</script>
and your routes similar to before:
#app.route('/sales/')
#app.route('/sales/<address>')
def get_sales(address="Nowhere"):
# do some magic here
# render template of sales
return "The address is "+address
However, this is not the best way of doing this kind of thing. An alternative approach is to have flask serve data and use a single-page-application framework in javascript to deal with the routes from a user interface perspective.
There is a difference between the request made when the form is submitted and the response returned. Leave the query string as is, as that is the normal way to interact with a form. When you get a query, process it then redirect to the url you want to display to the user.
#app.route('/sales')
#app.route('/sales/<address>')
def sales(address=None):
if 'address' in request.args:
# process the address
return redirect(url_for('sales', address=address_url_value)
# address wasn't submitted, show form and address details
I'm not sure there's a way to access the query string like that. The route decorators only work on the base url (minus the query string)
If you want the address in your route handler then you can access it like this:
request.args.get('address', None)
and your route handler will look more like:
#pp.route('/sales')
def get_sales():
address = request.args.get('address', None)
But if I were to add my 2 cents, you may want to use POST as the method for your form posting. It makes it easier to semantically separate getting data from the Web server (GET) and sending data to the webserver (POST) :)

403s resubmitting a form after login

I get a 403 under the following repro steps:
While logged out, try to submit a Django form that generates a validation error
Log in or signup for a valid account
Using the browser, go BACK to the page with the validation error
Resubmit the form
Results: 403 error. This is most likely expected behavior, however I'm looking for a more graceful way to handle this. Is there a good way to catch this and resubmit the form as the logged in user?
I have seen this question asked in the context of many frameworks, and the only elegant solution is JavaScript.
With JavaScript, you could store the input values in localStorage. Then on successful form submit event, clear those values. If the form is loaded with those values existing in localStorage (the form submission returned 403, and the user went back to the form page), then automatically populate the form with the values.
Its not really that complex to implement, just more work. I believe there are JS libraries based on this idea...
Give all your form elements a classname. In the example I will use store-data. This can be set in forms.Widget.attrs if you define your form in django, or just with the class attribute on input elements if you write your own html.
On submit, add an item named formData to localStorage. formData is a JS object mapping form field element ids with the classname from above to the element values.
If the form is submitted and processed as valid, on the redirect page remove formData from localStorage with localStorage.removeItem().
When loading the form page (this would be where the user went back to the form after a 403), if formData exists in localStorage then load the values into the form fields.
Here is an example form with this implemented:
<form name="myForm" action="{% url 'myapp:form_submit' %}" onsubmit="return storeData()">
<label>Name: </label>
<input type="text" class="store-data" id="inputName" />
<label>Description: </label>
<textarea class="store-data" id="textareaDescription"></textarea>
<input type="submit" />
</form>
<script>
function storeData() {
var elements = document.getElementsByClassName("store-data");
var formData = {};
// store element ids and values in formData obj
for (var i = 0; i < elements.length; i++) {
formData[elements[i].id] = elements[i].value;
}
// store formData to localStorage as string
localStorage.setItem('formData', JSON.stringify(formData));
}
// if the localStorage item has already been set, then the user tried to submit and failed
if (localStorage.getItem('formData')) {
formData = JSON.parse(localStorage.getItem('formData'))
// set all the form elements to the values that were stored when the user tried to submit
for (var key in formData) {
document.getElementById(key).value = formData[key];
}
}
</script>
And on the redirected success page, be sure to remove the formData item. Otherwise, any time the user goes back to the form the values will be loaded into the fields. (I suppose this may be a desired behavior, but I doubt it.)
<script>
localStorage.removeItem('formData');
</script>
Well, yes, it's expected behaviour. When you login, new csrf_token is generated. And when you navigate back to page with validation error, it still contains old csrf_token in <input type="hidden" name="csrfmiddlewaretoken" value="old_token" />. So you submit form with invalid csrf_token and get 403 error.
I can suggest two options for you (none of them I like)
Disable new csrf_token generation on login. Just place request.META['CSRF_COOKIE_USED'] = False after login(request, user) in your loggin view.
Disable csrf protection via decorator for your single view, or globally by removing csrf middleware from your settings.py.

How to upload image using rest web services in symfony

I am trying upload image using rest web service in my symfony application. I have tried the following code but it is throwing the error undefined index photo. I want to know what is the right way to do it.
I have followed how to send / get files via web-services in php but it didn't worked.
Here is the my html file with which am hitting the application url:
<form action="http://localhost/superbApp/web/app_dev.php/upload" enctype='multipart/form-data' method="POST">
<input type="file" name="photo" ></br>
<input type="submit" name="submit" value="Upload">
</form>
And my controller method is like:
public function uploadAction(){
$request = $this->getRequest(); /*** get the request method ****/
$RequestMethod = $request->getMethod();
$uploads_dir = '/uploads';
foreach ($_FILES["photo"]["error"] as $key => $error) {
if ($error == UPLOAD_ERR_OK) {
$tmp_name = $_FILES["photo"]["tmp_name"][$key];
$name = $_FILES["photo"]["name"][$key];
move_uploaded_file($tmp_name, $uploads_dir."/".$name);
}
}
}
If you are using Symfony, you should use Symfony forms to do this. In your example, you put an URL which is pointing to app_dev.php, but that url doesn't work in production mode. In the Symfony cookbook there is an article explaining how upload files, which you should read:
http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html
When you have done this, you can upload images via Rest WebService using the route specified for your action, specifying the Content-Type to multipart/form-data, and the name of the field which you add the image would be something like this package_yourbundle_yourformtype[file].

change default form email type regex in symfony2

Using Symfony 2.3.4.
When I create a form with a field in it that's supposed to process emails I go and use the default email type:
builder->add('email', 'email', array(
'label' => 'Email',))
with only this, it successfully validates user inputs, only not the way I want, meaning:
how it works:
me --> notallowed
me#gmail --> allowed
how I need it to work:
me --> notallowed
me#gmail --> notallowed
me#gmail.com --> allowed
summing up:
I figured what I need is to change/customize the default regex that validates this which I guess is deep in one of the many files in symfony.
appreciate any tips regarding this, thanks
Actually, the validation that you are seeing here is the browser based HTML5 validation. The message that pops up if me is entered comes right from your browser, no Symfony involved. I find HTML5 validation unreliable for the most part. Best practice is to validate on the server side, and use some type of javascript validation for the client side.
for more info on setting up server side validation, see the symfony docs, they give some great examples and it is very useful.
You can handle email validation by javascript . Call any method on form submit like
function validate(){
var email=$('#email').val();
if(email!=""){
var re =/^([a-zA-Z0-9_\.\-])+\#(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
if (!re.test(email)) {
alert('please Enter Valid email address');
}
}
<form onSubmit="return validate();">
<input type="text" name="email" id="email" placeholder="Please Enter your Email address" />
</form>
Please refer this following link for form field type email
Symfony form type email
If you want jquery validation for email
$('#formId').validate({
errorClass: 'help-block',
rules: {
'textFieldName': {
required: true,
email: true
}
},
messages: {
'textFieldName': {
email: "Invalid Email Address"
}
},
highlight: function (element) {
$(element).parent().parent().removeClass("success").addClass("error");
},
unhighlight: function (element) {
$(element).parent().parent().removeClass("error").addClass("success");
}
}); // validate

User redirect with POST in iframe

I am building one of my first MVC 4 applications and I need some help with redirecting users.
I have a windows form application where I use a AxSHDocVw.AxWebBrowser to redirect the user to a specific URL , a SOAP web service to be precise, aswell as sending HTTP POST and HEADER data aswell.
This is done like so:
oHeaders = "Content-Type: application/x-www-form-urlencoded" + "\n" + "\r";
sPostData = "ExchangeSessionID=" + SessionID;
oPostData = ASCIIEncoding.ASCII.GetBytes(sPostData);
axWebBrowser2.Navigate2(ref oURL, ref o, ref o, ref oPostData, ref oHeaders);
I am looking to replicate this functionality in my MVC application, but am unsure of the how this can be done.
I was hoping to have this within an iframe, but can't find a way of sending the POST and HEADER data from this. This is what I have been trying so far:
Controller
ViewBag.URL = TempData["URL"];
ViewBag.SessionID = TempData["SessionID"];
ViewBag.FullURL = TempData["URL"] + "?ExchangeSessionID=" + TempData["SessionID"];
return View();
View
<iframe src="#ViewBag.FullURL" width="100%" height="500px"></iframe>
Basically I was trying to append the data to the end of the URL hoping this would work for the HTTP POST part. This is what I ended up with:
https://www.myurl.aspx?ExchangeSessionID=87689797
The user is being directed to the page, but the web service is giving me an error ( which tells me it is now receiving the POST data).
Can some please help me to try and fix this, or even give me advice on how to go about this another way. Like I said, I'm fairly new to MVC applications and I'm not entirely sure what I'm tryin to do is even possible.
Any help is appreciated. Thanks
I've decided to answer this question myself incase anybody is looking to do something similar in the future.
The first step was to create my iframe:
<iframe name="myframe" src="" width="100%" height="700px"></iframe>
Next I want to create a form with a button which, when pressed, will post the data to the url while targeting the iFrame (Note the target attribute of the form):
<form action="#ViewBag.URL" method="post" target="myframe">
<input type="hidden" name="ExchangeSessionID" value="#ViewBag.SessionID" />
<input type="submit" value="Submit" />
</form>
So what happens is, when the button is pressed, the form posts the ExchangeSessionID to the target URL and then the page response is displayed inside the iFrame.