POST gets null value - asp.net

I don't know the exact format of the incoming JSON and have no control of it. I eventually need an object to match the incoming JSON format.
My thought was to treat it as a string and write it to a file, whatever format it is, so I can examine it and create an object to match.
From Fiddler, I'm sending this:
URL: https://localhost:44351/api/values
Headers
User-Agent: Fiddler
Host: localhost:44351
Content-Length: 13
Content-Type: application/json
Body
{name='test'}
'Get' works and returns properly. 'Post' gets called but when I debug it, it gets a null value for the string.
It creates the file but, understandably, it is empty.
public class ValuesController: ApiController
{
public string Get(int id)
{
return "value=" + id.ToString();
}
public IHttpActionResult Post([FromBody] string value)
{
File.WriteAllText(#"C:\temp\Import.txt", value);
return Ok();
}
or
public IHttpActionResult Post([FromBody] GenericText value)
{
File.WriteAllText(#"C:\temp\Import.txt", value.Name);
return Ok();
}
public class GenericText
{
public string Name { get; set; }
}
Routing
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
How do I get access to the incoming JSON so I can write it out to the file?

You are posting a json object: {name='test'} and expect the body to be of type string in the controller. There are two possible solutions to your problem:
post a string and keep expecting a string in the controller.
keep posting the json object with the property name of type string, and change the expected type in the controller.
which would look like:
public class MyRequestObject
{
public string Name {get;set;}
}
public IHttpActionResult Post([FromBody] MyRequestObject value)
{
File.WriteAllText(#"C:\temp\Import.txt", value.Name);
return Ok();
}

I never did solve this directly, but was able to work around it.
If your controller descends from Controller, you get access to Request
//
// Summary:
// Gets the HttpRequestBase object for the current HTTP request.
//
// Returns:
// The request object.
public HttpRequestBase Request { get; }
I used it like so
value = new StreamReader(Request.InputStream).ReadToEnd();
Note that in some cases you need to reset the input stream to the beginning to be able to read any content, but I didn't need that step in the final solution.

Related

No resource found error while calling WEB API

I created a WEB API for getting some list . I created another API for login which is working fine. But whenever call the API which provide me some list, it will show error as
No HTTP resource was found that matches the request URI 'http://localhost:85476/API/EmployeeMobile/GetEmployeeForMobile,
No action was found on the controller 'EmployeeMobile' that matches the request.
My controller:
public class EmployeeMobileController : ApiController
{
private PCommon _pCommon;
IEmployeeBusiness _employeeBusiness;
Mapper _mapper;
public EmployeeMobileController()
{
_pCommon = new PCommon();
_employeeBusiness = new EmployeeBusiness();
_mapper = new Mapper();
}
[HttpPost]
public string GetEmployeeForMobile(string userID, string connectionString)
{
DataSet dsEmployee = _employeeBusiness.GetAllEmployeeForMobile(Guid.Parse(userID), connectionString);
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
object routes_list = (object)json_serializer.DeserializeObject(JsonConvert.SerializeObject(dsEmployee.Tables[0]));
return JsonConvert.SerializeObject(routes_list);
}
}
My WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
My PostMan Calling details
http://localhost:61557/API/EmployeeMobile/GetEmployeeForMobile
Body: {"userID":"fc938df0-373c559f","connectionString":"Data\tSource=WIN\\MSSQLSERVER2016;Initial\tCatalog=PDefault;User\tID=db;Password=db123"}
Please help me to recover this problem.
Please note, WebAPI doesn't support binding of multiple POST parameters. You are defining your POST like a GET method. Change it to return a single Model
Your model should look like following.
public class Input
{
public string uSerID { get; set; }
public string connectionString { get; set; }
}
Now change the POST method like
[HttpPost]
public string GetEmployeeForMobile(Input request)
{
//Your implementation here
}
and you JSON for the post should look like following.
{uSerID:"abc", connectionString :"xyz"}

How to write an api action to create an entity in Web API

I have a question regarding creating an HTTP POST action in WEB API (ASP.NET). Let's say I have an entity that is called 'category'
the Model class of it is like the following:
public class Category
{
// Navigation Properties
[Required]
public int CategoryID { get; set; }
[Required]
public string CategoryName { get; set; }
public string CategoryDescription { get; set; }
public DateTime DeletedAt { get; set; }
// Scale Properties
}
In the controller I put all the actions that I want to interact with this entity 'category'. One of the actions is to create a category (HTTP POST) like the following:
[HttpPost]
[ActionName("createCategory")]
public IHttpActionResult createCategory(Category category)
{
if (ModelState.IsValid){
using (SqlConnection connection = WebApiApplication.reqeustConnection("ConStrMRR")) {
using (SqlCommand command = new SqlCommand("createCategory", connection)) {
try {
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#CategoryName", category.CategoryName));
command.Parameters.Add(new SqlParameter("#CategoryDescription", category.CategoryDescription));
command.ExecuteNonQuery();
return Ok("A category has been created");
} catch (Exception e) {
throw e;
} finally {
connection.Close();
}
}
}
}
return Content(HttpStatusCode.BadRequest, "Any object"); ;
}
As you can see there is I am passing 2 parameters to the function.. however, I am not sure if this is the right way to do it.. In other languages I know that you can see the body parameters that it's been sent with the request through a global variable.
I am using POSTMAN to test my requests. I wanna send the url http://localhost:64611/api/categories/createCategory with body (raw) like the following
{
"categoryName":"my category",
"categoryDescription":"my description"
}
The response that I am getting from is
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:64611/api/categories/createCategory'.",
"MessageDetail": "No action was found on the controller 'Categories' that matches the request."
The Route Template that I have is
config.Routes.MapHttpRoute(
name: "defaultApiRoutes",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = #"\d+" } // Only matches if "id" is one or more digits.
);
My question is what should I change in my controller action to make this request work?
you have a number of options.
go for a RESTful approach. This means you will have a Category controller with a method called POST.
public IHttpActionResult POST(Category category)
{
if ( ModelState.IsValid )
{
//here you actually create the thing.
}
}
you access this on http://localhost:64611/api/category with a POST request
You define a route:
[HttpPost]
[Route("createCategory")]
public IHttpActionResult whatever(Category category)
{
// code here
}
then you can post to http://localhost:64611/api/createCategory
Note how you use a model class, if you use it like I did, every property will be validated with the rules you defined.
I only mentioned RESTful because this is a standard used to develop APIs. You don't have to use it. The second option is probably what you're looking for. Just use the route attribute and you should be golden.
As for the body of the request, that's fine, JSON will work as expected. Try it with Postman.

Posting to MVC Controller, ViewModel stays null

I have this ASP.NET MVC controller action and viewmodel:
public JsonResult Upload(UploadModel MyModel)
{
//do stuff with MyModel
}
public class UploadModel
{
public string Name;
}
And in Angular, a method for submitting a form to this action:
function onSubmit() {
console.log(vm.model);
$http.post('/Home/Upload', vm.model).
then(function (response)
{
// do stuff with response
});
};
When I log vm.model, it looks like this:
{ Name : "Some cool name" }
It looks exactly the same in the request payload. But when I post this object to the Upload method, Name appears to be null. However, when I change the Upload method to accept just a string instead of a viewmodel:
public JsonResult Upload(String Name)
{
//do stuff with Name
}
And post the exact same object to it, it does get recognized.
What is going on? Why isn't MVC recognizing my JS object as a viewmodel?
Name is a field, not a property (no getter/setter) so the DefaultModelBinder cannot set the value. Change it to
public class UploadModel
{
public string Name { get; set; }
}
You should serialize your form data and then post
var cpformdata = $("#Myform form").serializeArray();
$.ajax({
url: url,
type: 'POST',
data: cpformdata,
success: function (data) {
}

Get routing information about a URL

I've got an ASP.NET MVC website that needs to display user-provided URLs stored in the DB. The way they're displayed will be different depending on how that URL would be routed if that URL refers to the website itself.
For example, supposing the website is foo.com:
URL stored in DB: foo.com/pie/3/nutrition
Controller is "pie"
Action is "nutrition"
ID is 3
The way the link is formatted depends on all three of these.
How would I extract this information correctly? Can I query the URL routing device?
Note: "Use a regular expression" type of answers don't interest me -- the site, action, or controller names could change, the website may be accessible through multiple site names and ports, etc...
You may find the RouteInfo class illustrated in this blog post useful:
public class RouteInfo
{
public RouteData RouteData { get; private set; }
public RouteInfo(Uri uri, string applicationPath)
{
RouteData = RouteTable.Routes.GetRouteData(new InternalHttpContext(uri, applicationPath));
}
private class InternalHttpContext : HttpContextBase
{
private readonly HttpRequestBase request;
public InternalHttpContext(Uri uri, string applicationPath)
{
this.request = new InternalRequestContext(uri, applicationPath);
}
public override HttpRequestBase Request
{
get { return this.request; }
}
}
private class InternalRequestContext : HttpRequestBase
{
private readonly string appRelativePath;
private readonly string pathInfo;
public InternalRequestContext(Uri uri, string applicationPath)
{
this.pathInfo = uri.Query;
if (string.IsNullOrEmpty(applicationPath) || !uri.AbsolutePath.StartsWith(applicationPath, StringComparison.OrdinalIgnoreCase))
{
this.appRelativePath = uri.AbsolutePath.Substring(applicationPath.Length);
}
else
{
this.appRelativePath = uri.AbsolutePath;
}
}
public override string AppRelativeCurrentExecutionFilePath
{
get { return string.Concat("~", appRelativePath); }
}
public override string PathInfo
{
get { return this.pathInfo; }
}
}
}
You could use it like this:
public ActionResult Index()
{
Uri uri = new Uri("http://foo.com/pie/3/nutrition");
RouteInfo routeInfo = new RouteInfo(uri, this.HttpContext.Request.ApplicationPath);
RouteData routeData = routeInfo.RouteData;
string controller = routeData.GetRequiredString("controller");
string action = routeData.GetRequiredString("action");
string id = routeData.Values["id"] as string;
...
}
From the section about unit testing in this: scott guthrie blog post
you can do something like this:
MockHttpContext httpContxt = new MockHttpContext("foo.com/pie/3/nutrition");
RouteData routeData = new routes.GetRouteData(httpContext);
where routes is the RouteCollection you used to initialize your routes in your application. Then you can interrogate routeData["controller"] etc
the post is about an early version of MVC, so the class names may have changed since then.

Pass a JSON array to a WCF web service

I am trying to pass a JSON array to a WCF service. But it doesn't seem to work. I actually pulled an array [GetStudents] out the service and sent the exact same array back to the service [SaveStudents] and nothing (empty array) was received.
The JSON array is of the format:
[
{"Name":"John","Age":12},
{"Name":"Jane","Age":11},
{"Name":"Bill","Age":12}
]
And the contracts are of the following format:
//Contracts
[DataContract]
public class Student{
[DataMember]public string Name { get; set; }
[DataMember]public int Age{ get; set; }
}
[CollectionDataContract(Namespace = "")]
public class Students : List<Student>
{
[DataMember]public Endorsements() { }
[DataMember]public Endorsements(IEnumerable<Student> source) : base(source) { }
}
//Operations
public Students GetStudents()
{
var result = new Students();
result.Add(new Student(){Name="John",12});
result.Add(new Student(){Name="Jane",11});
result.Add(new Student(){Name="Bill",12});
return result;
}
//Operations
public void SaveStudents(Students list)
{
Console.WriteLine(list.Count); //It always returns zero
}
It there a particular way to send an array to a WCF REST service?
I had similar issue.
I was calling the service from a browser and the problem was Firefox dynamically changing the request content-type from 'application/json' to 'application-json;charset=utf-8'.
If you are calling the service from a browser, test it with non-firefox browser and if that was the case you need to remove the charset from the request content-type header

Resources