sending form data with file and boolean values in angular2 - asp.net

I have a form where the user selects from a set of check boxes and also selects a picture. I'm sending this form from an angular2 front-end to an asp.net core web api backend. The issue i am having is that when i send the data, only the image file is sent, all the check box data which is in boolean is ignored. It's my first time doing this so i'm not sure how to handle it.
Below is the code i am using for adding the data to a form data
var formData = new FormData();
formData.append('ReturnFaceLandMarks', this.formViewModel.ReturnFaceLandmarks);
formData.append('ReturnFaceId', this.formViewModel.ReturnFaceId);
formData.append('age', this.formViewModel.age);
formData.append('facial_hair', this.formViewModel.facial_hair);
formData.append('gender', this.formViewModel.gender);
formData.append('glassed', this.formViewModel.glassed);
formData.append('head_pose',"false");
formData.append('smile', "true");
formData.append('file', this.formViewModel.img);
and down here is the post request
detect(data: any): Promise<any>
{
return this.http.post(this.serverUrl+"face/detect/", data, { headers: this.headers })
.toPromise()
.then(response => {
console.log(response);
})
.catch(this.handleError);
}
The file gets sent to my web api, but the only file i see there is the image file.Below is my request payload.

I ran into similar issues working with Angular and .Net
The solution that worked best for me was to either create a class (model) that the FormData mapped to or to specify the web api controller method parameters with the [FromForm] attribute.
public IActionResult Upload(IFormFile file, [FromForm] bool smile) {
...
}

Related

How to fire a function on every request in .net core minimal API

Just starting out with .net core minimal API and trying to solve all the little issues that will have to work before it's usable in my situation.
This API will be accessible from multiple tenants so I need to check the calling domain on every request (including when authenticating via user/pass) and then set some variables that need to be accessible from all routes.
Can anyone point me in the right direction because I can't find any information on how this is achieved.
Thanks
UPDATE - some examples of where the middleware works and doesnt
So this is the middleware
app.Use((context, next) =>
{
// Lets assume the domain info is in the query string
context.Items["domain"] = context.Request.Query["domain"];
return next();
});
and this code works just fine
app.MapGet("/", async handler =>
{
// Get the domain and then return back the formatted string with the domain name
var domain = handler.Items["domain"];
await handler.Response.WriteAsJsonAsync($"Hello World! {domain}");
});
When I have an endpoint decorated with [AlowAnonymous] I have to put handler in brackets like this
app.MapGet("/whatever",
[AllowAnonymous] async (handler) =>
{
// Get the domain and then return back the formatted string with the domain name
var domain = handler.Items["domain"];
await handler.Response.WriteAsJsonAsync($"Hello World! {domain}");
});
If I have multiple class objects it borks (this has the httprequest, my db class and a login class). The error is Delegate 'RequestDelegate' does not take 4 arguements.
app.MapGet("/whatever2",
[AllowAnonymous] async (handler, HttpRequest request, SqlConnection db, Login login) =>
{
// Get the domain and then return back the formatted string with the domain name
var domain = handler.Items["domain"];
await handler.Response.WriteAsJsonAsync($"Hello World! {domain}");
});
Thanks
You can add a piece of middleware in the request pipeline to fetch any details needed for mapped APIs. For example...
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use((context, next) =>
{
// Lets assume the domain info is in the query string
context.Items["domain"] = context.Request.Query["domain"];
return next();
});
app.MapGet("/", async handler =>
{
// Get the domain and then return back the formatted string with the domain name
var domain = handler.Items["domain"];
await handler.Response.WriteAsJsonAsync($"Hello World! {domain}");
});
app.Run();
The above adds middleware that runs first before attempting to map to any of the endpoints.

Sending both files and model from Angular 4 to ASP.NET Core backend

I've been trying to make a form that contains both file inputs (in this case images) and text inputs. Text inputs are part of the model which I want to send to server. On the backend I'm using ASP.NET Core 2.0.
Here is my backend code:
[HttpPost]
public async Task<IActionResult> PostEditProfile([FromForm] EditProfileViewModel model, IFormFile profileImage, IFormFile bannerImage)
{
//Some code
}
When I call this API using Postman (where I set model's properties and images in form-data), everything works fine. But when I try to call it using Angular code, all the parameters are null. Here is my Angular 4 code:
var formData = new FormData();
for (var propertyName in editProfile) {
if (editProfile[propertyName]){
formData.append(propertyName, editProfile[propertyName].toString());
}
}
formData.append('profileImage', profileImage);
formData.append('bannerImage', bannerImage);
return this.authHttp.post(this.baseUrl + 'api/Account/PostEditProfile', formData)
.toPromise()
.then(response => {
var userInfo = response.json() as UserInfo;
this.setUserInfo(userInfo);
return userInfo.userName;
})
.catch(this.handleError);
When I looked at the request using Fiddler, I noticed that when I send request using Angular 4, Content-type header is not set to multipart/form-data (and when I use Postman it is). I've tried setting it, but it was set to application/json again.
I've also tried without [FromForm], but also no luck. I'm not sure what to do next.

use json format in an URL

I am building a rest API with asp.net my problem is that when I try to add a student to my database like that :
http://localhost:50001/api/Students?&FirstName=cc&LastName=cc&Email=student10#gmail.com&DropOut=false&Live=false&ClassId=1&ImageId=1
I get "the value variable is null",
this is my code to add a student:
// Get All Students
[Route("api/Students")]
public IEnumerable<Student> Get()
{
return _StudentService.Queryable().ToList();
}
// Insert Student
[Route("api/Students/")]
public IEnumerable<Student> Post(Student value)
{
cc.Students.Add(value);
cc.SaveChanges();
return Get();
}
I have used "Fiddler web Debugger" to test my URLs an it works only in this way:
now If I have an angularJS client that tries to add a new student to the database,how can I send data as a json format in an URL
this is how I add a new student from my client angularJS:
$http({method: 'POST', url: 'http://localhost:50001/api/Students?&FirstName=cc&LastName=cc&Email=student10#gmail.com&DropOut=false&Live=false&ClassId=1&ImageId=1})
.success(function (data) {
console.log("success");
}).error(function (data, status, headers, config) {
console.log("data error ...");
});
thanks a lot for help
If you are saying you want a true Rest API you should continue to use the POST verb as it is more semantically right for creating a new student.
Passing a new student on the URL is possible but not in the configuration you have provided.
Your API method expects a POST request and that the new student be located in the HTTP body.
Just configure your angular call to use jsonData and post it to your API.

AngularJs Windows Intranet User

Using ASP.Net Web API service I can get the current windows user using the following.
public class UserController : ApiController
{
public string Get()
{
var id = WindowsIdentity.GetCurrent();
return id.Name;
}
}
My question is how can I find the current user logged in a angularjs controller without having to call the web api service?
myApp.controller('TestCtrl', function ($scope) {
$scope.getUserData = function(){
$http({method: 'GET', url: '/URLtoResourceInWebService'}).
success(function(data, status, headers, config) {
//use the data of your User object
}).error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
}); //End of Controller
Here is a real simple example of how to hit an endpoint in Angular and get back a resource from a WebService. I would actually suggest extracting out your API calls however into a service rather than using the "$http" because then you centralize them in one place, and if you switch API's your code doesn't break all over. Let me know if this helps.

A simple POST request to Web API not hitting the API at all

From my MVC application, I am trying to make a POST request to these sample end-points (actions) in an API controller named MembershipController:
[HttpPost]
public string GetFoo([FromBody]string foo)
{
return string.Concat("This is foo: ", foo);
}
[HttpPost]
public string GetBar([FromBody]int bar)
{
return string.Concat("This is bar: ", bar.ToString());
}
[HttpPost]
public IUser CreateNew([FromBody]NewUserAccountInfo newUserAccountInfo)
{
return new User();
}
Here's the client code:
var num = new WebAPIClient().PostAsXmlAsync<int, string>("api/membership/GetBar", 4).Result;
And here's the code for my WebAPIClient class:
public class WebAPIClient
{
private string _baseUri = null;
public WebAPIClient()
{
// TO DO: Make this configurable
_baseUri = "http://localhost:54488/";
}
public async Task<R> PostAsXmlAsync<T, R>(string uri, T value)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_baseUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
var requestUri = new Uri(client.BaseAddress, uri);
var response = await client.PostAsXmlAsync<T>(requestUri, value);
response.EnsureSuccessStatusCode();
var taskOfR = await response.Content.ReadAsAsync<R>();
return taskOfR;
}
}
}
I have the following default route defined for the Web API:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
UPDATE
My code breaks into the debugger until the time the PostAsXmlAsync method on the System.Net.HttpClient code is called. However, no request shows up in Fiddler.
However, if I try to compose a POST request in Fiddler or try to fire a GET request via the browser to one of the API end-points, the POST request composed via Fiddler tells me that I am not sending any data and that I must. The browser sent GET request rightly tells me that the action does not support a GET request.
It just seems like the System.Net.HttpClient class is not sending the POST request properly.
One of the most usual problems is that you don't use the appropriate attribute.
Take into account that there are attributes for ASP.NET MVC and ASP.NET Web API with the same name, but which live in different namespaces:
For Web API you must use the one in System.Web.Http
For MVC, the one in System.Web.MVc
This is a very very usual error, and it affects to allkind of things that exist for both MVC and Web API. So you must be very careful when using something which can exists in bith worlds (for example filters, attributes, or dependency injection registration).
I experienced a similar problem (may not be same one though). In my case, I hadn't given name attribute to the input element. I only figured that out when fiddler showed no post data being sent to the server (just like your case)
<input id="test" name="xyz" type="text" />
Adding the name attribute in the input tag fixed my problem.
However, there is one more thing to note. WebAPI does not put form data into parameters directly. Either you have to create an object with those properties and put that object in the parameter of the post controller. Or you could put no parameters at all like this:
[Route("name/add")]
public async Task Post()
{
if (!Request.Content.IsMimeMultipartContent())
{
return;
}
var provider = PostHelper.GetMultipartProvider();
var result = await Request.Content.ReadAsMultipartAsync(provider);
var clientId = result.FormData["xyz"];
...
Try changing the FromBody to FromUri.
If the parameter is a "simple" type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string.
For complex types, Web API tries to read the value from the message body, using a media-type formatter.
Remove FromBody at all and don't make any restrictions in passing parameters (it can be passed at this time either in uri, query string or form submissions (which is kinda a similar to query strings)
[HttpPost]
public string GetFoo(string foo){...}
It will be implicitly parsed and passed.

Resources