Web API method not returning the response - asp.net-mvc

I have a requirement to use Web API. I have implemented Add functionality successfully , and now in the Edit . I am calling the PUT method from my mvc controller thorough and intermediate class and which returns
return Request.CreateResponse(HttpStatusCode.OK); This is the return from my PUT method
public HttpResponseMessage SampleEdit(int sampleId, Sample sample)
{
string uri = baseUri + "Sample/" + sampleId;
using (HttpClient httpClient = new HttpClient())
{
Task<HttpResponseMessage> response = httpClient.PutAsJsonAsync<Sample>(uri, sample);
return **JsonConvert.DeserializeObjectAsync<HttpResponseMessage>(response.Result.Content.ReadAsStringAsync().Result).Result;**
}
}
Here if i debug the put method is called and it is setting the status .
HttpResponseMessage message =
DatabaseService.SampleEdit(sample.SampleID,sample);
This message is coming as null if the return statement in PUT is Request.CreateResponse(HttpStatusCode.OK);
If i use
Request.CreateResponse(HttpStatusCode.OK,sample);
instead it is returning the status. What would be the issue

Related

Cannot get a response from a Web API call

I have the following in the TreeController controller in a small web API:
[HttpGet("GetDirectories")]
public IActionResult GetDirectories()
{
var baseDir = _config["QuickShare:BaseDir"];
if (string.IsNullOrWhiteSpace(baseDir))
{
throw new InvalidOperationException("'QuickShare:BaseDir' is not configured");
}
var ret = GetDirectories(baseDir); ;
return Json(ret);
}
private List<DirectoryInfo> GetDirectories(string parentDir)
{
var dirInfo = new DirectoryInfo(parentDir);
return dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly).ToList();
}
When I try and call this action from Postman, I get told
Could not get any response There was an error connecting to
http://localhost:59243/api/Tree/GetDirectories.
Now the default, test, controller that comes with the project template is unchanged:
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] {"value1", "value2"};
}
...
}
And when I have the API running in Visual Studio, I can get a proper response from the Values controller, but not from the TreeController, yet they are almost exactly the same. And, when I call the Tree/GetDirectories` action, a breakpoint in that action method is hit, and I can single step through the very few lines that my method has, and they all execute fine.
The problem only becomes apparent when that last line of the action executes:
return Json(ret);
Then I get shown that Postman Could not get any response despite no exception being raised; while debugging the code, it looks like everything should work fine, and the requests to the Values controller work fine.
Your action method should return either the specific result type (JsonResult when you return Json ) or IActionResult.
Example:
[HttpGet("GetDirectories")]
public JsonResult GetDirectories()
{
var baseDir = _config["QuickShare:BaseDir"];
if (string.IsNullOrWhiteSpace(baseDir))
{
throw new InvalidOperationException("'QuickShare:BaseDir' is not configured");
}
var ret = GetDirectories(baseDir);
return Json(ret);
}
OR
[HttpGet("GetDirectories")]
public IActionResult GetDirectories()
{
var baseDir = _config["QuickShare:BaseDir"];
if (string.IsNullOrWhiteSpace(baseDir))
{
throw new InvalidOperationException("'QuickShare:BaseDir' is not configured");
}
var ret = GetDirectories(baseDir) ;
return Ok(ret);
}
You can get more help from Microsoft Documentation: Formatting Response Data

MVC Post Request how to get Request Content if it's different to that expected by the Default ModelBinder

I have this MVC WebApi action:
PostTrips(List<Trip> trips)
When a list of trips is sent through everything works fine. If, however, someone is trying to post incorrect data, e.g just an object {} then trips is null - this is fine, but I would like to log the data that the user tried to push.
I tried to get it using string requestData = Request.Content.ReadAsStringAsync().Result; but it can only be called once, and I guess the default model binder is calling it to try an map it to my List<Trip>, as when I call it, the result is always null, even though I know I'm passing something in.
Does anyone know of another way to get the posted data again?
I got around this my removing the parameter List<Trip> trips from the action so I had:
public async Task<HttpResponseMessage> PostTrips()
{
}
This bypasses the default model binder and allows you to get the unmodified request content using:
string requestContent = await Request.Content.ReadAsStringAsync();
You can then do what ever you need with this - I wanted to log the data for error tracking.
To create the actual List<Trip> trips I then used Newtonsoft.Json to deserialise the string into a list:
List<TravelTrackerTrip> appTrips = JsonConvert.DeserializeObject<List<TravelTrackerTrip>>(requestContent);
Full example:
public async Task<HttpResponseMessage> PostTrips()
{
HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
List<Trip> appTrips = null;
string requestContent = await Request.Content.ReadAsStringAsync();
try
{
appTrips = JsonConvert.DeserializeObject<List<Trip>>(requestContent);
}
catch(Exception ex)
{
//ERROR LOGGING HERE...
//QUIT - Return failure response
}
try
{
//Success - do whatever we need
}
catch(Exception ex)
{
//ERROR LOGGING HERE...
//QUIT - Return failure response
}
//Return success response
}

Programatically authenticate AzureAd/OpenId to an MVC controller using C# and get redirect uri

I have overridden the built in WebClient as below. Then I call it
public class HttpWebClient : WebClient
{
private Uri _responseUri;
public Uri ResponseUri
{
get { return _responseUri; }
}
protected override WebResponse GetWebResponse(WebRequest request)
{
WebResponse response = base.GetWebResponse(request);
_responseUri = response.ResponseUri;
return response;
}
}
Then I consume it like this:
using (HttpWebClient client = new HttpWebClient())
{
client.Headers[HttpRequestHeader.Authorization] = $"Bearer { _token }";
client.Headers[HttpRequestHeader.ContentType] = "application/json";
client.UploadData(_url, Encoding.UTF8.GetBytes(_data));
string queryString = client.ResponseUri.Query.Split('=').Last();
}
The response uri comes back with "https://login.microsoftonline" rather than url returned from the MVC controller with a query string, as it is authenticating first with that bearer token using AzureAd/OpenId. If i call it twice it returns the original _url but not the redirected one. If I remove AzureAd authentication it works fine. Is there a way to force the response uri to come back as what the MVC controller sets it to?
Assuming you use the 'UseOpenIdConnectAuthentication' and configuring it to use AAD authentication, you can modify the redirect uri by setting Notifications.RedirectToIdentityProvider, something like:
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = async _ =>
{
_.ProtocolMessage.RedirectUri = _.Request.Uri.ToString();
}
}
If you use something else , or maybe I didn't understand your problem - please supply more information

using angular $http get with asp net web api

I am attempting to use an asp web api to populate an html table using angular. everything works great if I debug in firefox (I'm assuming because my web service is being returned in json) however in ie and chrome it does not load (the web service returns xml in these browsers). In the webapiconfig I attempted to always make the service return json by adding.
Dim appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(Function(t) t.MediaType = "application/xml")
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType)
this appears to work when I navigate to the api in all browsers it is returning json however the $http get is still now working in chrome and ie.
in ie I get the following error
Unhandled exception at line 21, column 406 in http://localhost:53175/Scripts/angular.min.js
0x800a139e - JavaScript runtime error: [$injector:nomod] http://errors.angularjs.org/1.3.13/$injector/nomod?p0=api%2Fproducts
here is my get
angular.module("api/products").constant("dataUrl", "sportstore.json").controller("sportsStoreCtrl", function ($scope, $resource, dataUrl) {
$scope.data = {};
var resultPromise = $resource(dataUrl);
resultPromise.success(function (data) {
$scope.data.products = data;
})
});
any thoughts?
additional info
here is my api controller
<pre>
Imports System.Net
Imports System.Web.Http
Imports apitoform.productRepository
Namespace Controllers
Public Class productController
Inherits ApiController
Private repo As productRepository = productRepository.Current
Public Function GetAllProducts() As IEnumerable(Of product)
Return repo.GetAll()
End Function
End Class
End Namespace
</pre>
and here is the j_son that is being returned ( I am working through the pro Angular book if it looks familiar)
Sorry this is c# code, but it should illustrate the basic idea for returning Json only from web api. It's actual code from one of my projects.
[Route("api/users/getbyemail/")]
public HttpResponseMessage GetByEmail(string email)
{
try
{
var result = _userService.GetByEmail(email);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value");
response.Content = new ObjectContent(typeof(IEnumerable<UserViewModel>), result ?? new List<UserViewModel>(), new JsonMediaTypeFormatter());
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
catch (Exception ex)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
}
So you are returning HttpResponseMessage with Json content.
I'm also doing similar in a scenario where I just need to return the data from one of the MVC controllers and that is even easier:
public ActionResult Get(string guid)
{
var profileVm = _profileService.Get(guid);
if (profileVm != null)
{
return Json(profileVm, JsonRequestBehavior.AllowGet);
}
return new HttpNotFoundResult();
}
angular.module with 1 parameter returns the module with that name - you need to define your module with a list of dependent modules (or empty array if none) like the following:
angular.module("api/products", [])...
The error referenced gives an error with details on the problem (angular's very good about their error messages): https://docs.angularjs.org/error/$injector/nomod?p0=api%2Fproducts

Accessing resources via Uri in Asp.net mvc

I am working on an ASP.NET MVC web application in which I have an object with a Uri property. The Uri contains a restful link to a resource in the following form:
/Repository/Dataset/5
The Dataset action of the Repository controller returns the contents of dataset 5 as Json.
How do I call this method from the Uri and interpret the response as Json from within the object?
Many thanks.
In server side action return JsonResult.
public ActionResult Dataset(int id)
{
// reository code
return Json(model);
}
client side call $.getJSON.
My opinion is that you should not call your controller from anywhere in code.In ASP.NET MVC Controller is there to accept request, take data and choose proper view to be returned back.
Maybe you should add method on repository that is returning already JSONized data, or introduce "Middle man" that can serialize data returned from repository so controller can call middle man to do the job. Then repository (or "Middle man") can be called from anywhere in code.
e.g.(used Json.NET for json serialization):
public class MiddleMan
{
IRepository repository
public MiddleMan(IRepository repository)
{
this.repository = repository;
}
public string GetJsonObjects(int id)
{
return JsonConvert.SerializeObject(repository.GetObject(id));
}
}
then controller (or anywhere in the code) can call this middle class:
public string Dataset(int id)
{
return new MiddleMan(repository).GetJsonObjects(id);
}
For the time being I'm going to implement a uri extension method something along these lines, creating a WebRequest object for the Uri.
public static string GetContent(this Uri uri)
{
var myRequest = (HttpWebRequest) WebRequest.Create(uri);
myRequest.Method = "GET";
WebResponse myResponse = myRequest.GetResponse();
var sr = new StreamReader(myResponse.GetResponseStream(), System.Text.Encoding.UTF8);
string result = sr.ReadToEnd();
sr.Close();
myResponse.Close();
return result;
}

Resources