I am calling an MVC3 controller action (JsonResult) from a console application. To make the call I am using a System.Net.Http.HttpClient and the PostAsJsonAsync method.
In the PostAsJsonAsync method I am passing a small poco instance.
It all works great apart for one thing.
My problem is that I cannot pick up the poco instance in the call to the the MVC3 controller action. Can anyone tell me how to do this?
Here's the code:
Calling code in console application:
var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:50285/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var user = new HashedUser { UserName = "userName", PasswordHash = "abcdef".GetHashCode() };
var response = client.PostAsJsonAsync("app/test", user).Result;
var txt = response.Content.ReadAsAsync<string>().Result;
Receiving Code in MVC3 project
public class AppController : Controller
{
public JsonResult Test(HashedUser json)
{
// Problem: json is always a new instance
// of HashedUser and not the one passed in
// from the call to this controller action.
return Json("qqq ppp 777 888" + json.UserName);
}
}
public class HashedUser
{
public string UserName { get; set; }
public int PasswordHash { get; set; }
}
You should serialize and send your POCO as JSon object. Use Newtonsoft.Json to do that. Here's some samples:
http://james.newtonking.com/pages/json-net.aspx
http://www.west-wind.com/weblog/posts/2012/Aug/30/Using-JSONNET-for-dynamic-JSON-parsing
Related
I'm building WebAPI & WebApp, both of them using ASP.NET Core 2.1
My Web App is trying to send post request to the Web API using ViewModel that contains IFormFile and other properties. I know I have to use MultipartFormDataContent to post IFormFile, but I don't know how to implement it with my ViewModel because my ViewModel has List of other model.
I already try to google some solutions, but I only found solutions with simple ViewModel without List like these :
https://stackoverflow.com/a/41511354/7906006
https://stackoverflow.com/a/55424886/7906006.
Is there any solution like
var multiContent = new MultipartFormDataContent();
var viewModelHttpContent= new StreamContent(viewModel);
MultiContent.Add(viewModelHttpContent, "viewModel");
var response = await client.PostAsJsonAsync("/some/url", multiContent);
so i don't have to add my property to MultipartFormDataContent one by one and post it as json.
Here's my Web App ViewModel
public class CreateDataViewModel
{
public string PrimaryKeyNumber{ get; set; }
public List<Currency> ListOfCurrency { get; set; }
public IList<DataDetail> dataDetails { get; set; }
[DataType(DataType.Upload)]
public IFormFile Attachment { get; set; }
//And other properties like Boolean, Datetime?, string
}
Here's my Web App controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(CreateDataViewModel viewModel)
{
//How to implement MultipartFormDataContent with my ViewModel in here ?
//My code below returns Could not create an instance of type Microsoft.AspNetCore.Http.IHeaderDictionary. Type is an interface or abstract class and cannot be instantiated. Path 'Attachment.Headers.Content-Disposition', line 1, position 723.
//It works fine if I don't upload a file
HttpResponseMessage res = await _client.PostAsJsonAsync<CreateDataViewModel>("api/data/create", viewModel);
var result = res.Content.ReadAsStringAsync().Result;
if (res.IsSuccessStatusCode)
{
TempData["FlashMessageSuccess"] = "Data have been submitted";
return RedirectToAction("Index", "Home"); ;
}
//Code for error checking
}
Here's my Web API controller that catches the post response using CreateDataViewModel as parameter.
[HttpPost]
[Route("[action]")]
public async Task<IActionResult> Create(CreateDataViewModel viewModel)
{
//Code to validate then save the data
}
don't know how to implement it with my ViewModel because my ViewModel has List of other model
You can refer to following code snippet and implement a custom model binder to achieve your requirement.
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(new StringContent(viewModel.PrimaryKeyNumber), "PrimaryKeyNumber");
multipartContent.Add(new StringContent(JsonConvert.SerializeObject(viewModel.ListOfCurrency)), "ListOfCurrency");
multipartContent.Add(new StringContent(JsonConvert.SerializeObject(viewModel.dataDetails)), "dataDetails");
multipartContent.Add(new StreamContent(viewModel.Attachment.OpenReadStream()), "Attachment", viewModel.Attachment.FileName);
var response = await client.PostAsync("url_here", multipartContent);
Implement a custom model binder to convert incoming request data
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
// code logic here
// ...
// ...
// fetch the value of the argument by name
// and populate corresponding properties of your view model
var model = new CreateDataViewModel()
{
PrimaryKeyNumber = bindingContext.ValueProvider.GetValue("PrimaryKeyNumber").FirstOrDefault(),
ListOfCurrency = JsonConvert.DeserializeObject<List<Currency>>(bindingContext.ValueProvider.GetValue("ListOfCurrency").FirstOrDefault()),
dataDetails = JsonConvert.DeserializeObject<List<DataDetail>>(bindingContext.ValueProvider.GetValue("dataDetails").FirstOrDefault()),
Attachment = bindingContext.ActionContext.HttpContext.Request.Form.Files.FirstOrDefault()
};
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
Apply it on API action method
public async Task<IActionResult> Create([ModelBinder(BinderType = typeof(CustomModelBinder))]CreateDataViewModel viewModel)
Test Result
Below soltuion worked for me:-
var multiContent = new MultipartFormDataContent();
var viewModelHttpContent= new StreamContent(viewModel);
multiContent.Add(viewModelHttpContent, "viewModel");
multiContent.Add(new StreamContent(file.OpenReadStream()), "Attachment", file.FileName);
var request = new HttpRequestMessage(HttpMethod.Post, "/some/url") { Content = multiContent};
var response = await client.SendAsync(request);
At Api end:-
public async Task Upload([FromForm] CreateDataViewModel postRequest)
I have a webApi and an MVC application.
The webApi has all the logic and the MVC application is just the presentation.
Im using RestSharp to get the data from the WebApi to the MVC application.
Im sharing here one method that retrieves all user information
public IUser getUserInformationLogin(string palsoftID)
{
var request = new RestRequest("FrontDeskLog/GetUserInfo/{PalsoftID}", Method.POST) { RequestFormat = DataFormat.Json };
request.AddParameter("PalsoftID", palsoftID, ParameterType.UrlSegment);
var response = service.Execute<User>(request);
return response.Data
}
everything is good until I add Serialize attribute to the User class, I need to make User serializable in order to use session state StateServer for my MVC application.
But after adding the serialize attr the above method always returns null.
If I debug i can see that in the Response. Content all data is there, but response.data returns a null object.
Any help will be very appreciated.
The Method in the webApi is this one
public IUser GetUserInfo(string PalsoftID)
{
FrontDeskDb data = new FrontDeskDb();
return data.getUsersInfo(PalsoftID);
}
this is the class Roles
public class Roles
{
public int RoleID { get; set; }
public string Role { get; set; }
public bool Main { get; set; }
}
Thank you.
I have the following Model
public class Customer
{
public string Name
{
get;set;
}
public string Address
{
get;
set;
}
}
The following WebAPI Method
[Route("PostCustomer")]
[HttpPost]
public Customer PostCustomer([FromBody]Customer c)
{
return c;
}
The following client code
Customer cust = new Customer() { Name = "abcd", Address = "test" };
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:11581");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsJsonAsync<Customer>("api/values/PostCustomer", cust);
The WebAPI Method never gets called and the response I get from the Web API says no content. When I try the same for a get it works fine.
I'm using a third party reporting engine (stimulsoft) that calls an action on a controller via POST. Inside of the form, many fields are sent for the mechanics of the third party. Inside of the action I need some parameters all my parameters are inside of the URL.
I want to be able to use the model binder inside of my action.
At the moment I'm getting each fields one by one using this methods
var queryString = HttpUtility.ParseQueryString(Request.UrlReferrer.Query);
var preparedBy = queryString["preparedBy"];
var preparedAt = (queryString["preparedAt"] != null) ? Convert.ToDateTime(queryString["preparedAt"]) : DateTime.Today;
I would prefer to use a model and binding using the UrlReferrer. I've created a UrlReferrerValueProvider to bind from the action. I've tried that, but I'm getting a NullReferenceException on binder.BindModel line
public class UrlReferrerValueProvider : NameValueCollectionValueProvider
{
public UrlReferrerValueProvider(ControllerContext controllerContext)
: base(HttpUtility.ParseQueryString(controllerContext.HttpContext.Request.UrlReferrer.Query), CultureInfo.InvariantCulture)
{
}
}
public ActionResultat GetReportSnapshot()
{
var bindingContext = new ModelBindingContext()
{
ValueProvider = new UrlReferrerValueProvider(ControllerContext),
ModelName = "MyReportModel",
FallbackToEmptyPrefix = true
};
var binder = new DefaultModelBinder();
var myReportModel = binder.BindModel(ControllerContext, bindingContext);
[...]
return new EmptyResult();
}
public class MyReportModel
{
public string PreparedBy {get;set;}
public DateTime PreparedAt {get;set;}
}
Edited based on comments.
public class MyReportModel
{
public string PreparedBy {get;set;}
public DateTime PreparedAt {get;set;}
}
public class UrlReferrerValueProvider : NameValueCollectionValueProvider
{
public UrlReferrerValueProvider(ControllerContext controllerContext)
: base(HttpUtility.ParseQueryString(controllerContext.HttpContext.Request.UrlReferrer.Query), CultureInfo.InvariantCulture)
{
}
}
public ActionResult GetReportSnapshot(MyReportModel model)
{
this.UpdateModel(model, new UrlReferrerValueProvider(ControllerContext));
return new EmptyResult();
}
I need to take GET fields from my asp.net web app (first name and last name). It needs to send that data from frontend(asp.net web app) using JSON to MVC 3 app. MVC 3 App would communicate with database, retrieve values and should serialize them into json object and POST to the front end(ASP.NET web app). Can anyone explain with a sample code how I would accomplish this?
You could use the WebClient class. It allows you to send HTTP requests to any web application. As far as the JSON part is concerned you will need a JSON serializer. You could use the built-in JavaScriptSerializer class or a third party such as Json.NET.
So let's suppose that you have the following controller action in your ASP.NET MVC 3 application that you want to invoke:
[HttpPost]
public ActionResult Foo(Bar bar)
{
...
return Json(new
{
status = "OK"
});
}
where the Bar class contains some properties (could be simple or complex types):
public class Bar
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Now you could invoke it like this from the client side:
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
var serializer = new JavaScriptSerializer();
var json = serializer.Serialize(new
{
firstName = "first",
lastName = "last"
});
var resultJson = client.UploadString("http://example.com/foo", json);
var result = serializer.Deserialize<Result>(resultJson);
}
where you would define the Result class to match the JSON structure returned by the application:
public class Result
{
public string Status { get; set; }
}