Cannot get a response from a Web API call - asp.net-mvc

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

Related

How to handle Http Status code when making use of ReadAsStringAsync()

I have a JavaScript client which makes Ajax call to a .net service (Lets call it First service). First service then makes call to another .net Controller (Call it Second Service). In this controller, I am throwing some exception. On the first line I am saying:
//Code from Second Service
[HttpPost]
public HttpResponseMessage Results(ParamsModel data)
{
throw new Exception("Exception for testing purpose");
}
//Code from First Service
[HttpPost]
public ActionResult Results(ParamsModel data)
{
var client = new HttpClient();
var task = client.PostAsJsonAsync(urlTemplate, data);
var result = task.Result.Content.ReadAsStringAsync().Result;
return Content(result, "application/json");
}
Problem: Though the Second Service is throwing error & returning 500 status code, The first servcie returns 200 status code to the JavaScript client. I am also not able to read the satus code returned by Second service as I only get string output.
Please suggest. I want to return 500 status code when there is an error.
You can implement error handling as follows in the HttpClient.
if (!task.Result.IsSuccessStatusCode)
{
if (task.Result.StatusCode == HttpStatusCode.InternalServerError)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "An error has occured.");
}
else
{
// Check for other status codes and handle the responses
}
}
else
{
// Success status code. Return success response.
}
Hope this helps.
Why can't you do an asynchronous action method?
[HttpPost]
public async Task<ActionResult> Results(ParamsModel data)
{
try
{
var client = new HttpClient();
var response = await client.PostAsJsonAsync(urlTemplate, data);
var json = await response.Content.ReadAsStringAsync()
return Content(result, "application/json");
}
catch(WebException ex)
{
//do note that the Response property might be null due to
// connection issues etc. You have to handle that by yourself.
var remoteErrorCode = ((HttpWebResponse)ex.Response).StatusCode;
Request.CreateErrorResponse(remoteErrorCode, "An error just happened");
}
}
But the thing is, with the layout of the first method it doesn't matter how you handle exceptions in the second one, as the first will always return "Internal Server Error".
To make it useful, you should typically return different error codes in the first method too.
You can return a HttpResponseException like this:
[HttpPost]
public ActionResult Results(ParamsModel data)
{
try
{
var client = new HttpClient();
var task = client.PostAsJsonAsync(urlTemplate, data);
var result = task.Result.Content.ReadAsStringAsync().Result;
return Content(result, "application/json");
}
catch (HttpResponseException ex)
{
return new HttpStatusCodeResult(ex.Response.StatusCode);
}
}
You will need to throw the right exception from your WebAPI controller:
[HttpPost]
public HttpResponseMessage Results(ParamsModel data)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
There are several status codes that can be thrown:
https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode.aspx

In ASP.Net Web API, how do I map multiple http query parameters to a single method parameter

We're using ASP.Net Web API to generate a feed and it includes the ability to do paging.
myfeed.com/afeed?page=2
My boss says "let's also allow users to use 'paged', because that's what WP uses." In addition, we're also using pageIndex in some of our older feeds. So what I'd like to do is accept all three.
myfeed.com/afeed?page=2
myfeed.com/afeed?paged=2
myfeed.com/afeed?pageIndex=2
I'd like to do is be able to write a clean Web API method, such as
public Foo Get(int page = 1)
{
//do some stuff
return foo;
}
without cluttering the method with page 'plumbing'. So I tried creating an ActionFilter
public override void OnActionExecuting(HttpActionContext actionContext)
{
object pageParam = new object(); //query["page"]
if (pageParam == null)
{
var altPageParam = GetPageParamUsingAlternateParams(actionContext);
if (altPageParam != null){}
//SetPageParam here
}
base.OnActionExecuting(actionContext);
}
private object GetPageParamUsingAlternateParams(HttpActionContext actionContext)
{
object result = new object();
object pageIndexParam = new object(); //Query["pageIndex"]
object pagedParam = new object(); ////Query["paged"]
if (pagedParam != null)
result = pagedParam;
else if (pageIndexParam != null)
result = pageIndexParam;
return result;
}
I didn't finish. As I was looking for the best way to get the query params, I stumbled into a big mistake!
OnActionExecuting is executed after int page = 1. Sure, I could override it in an ActionFilter, but that would lead to confusion down the road. I really want to be able to do a simple flow through the URI query parameters that goes from
page -> paged -> pageIndex -> default value in method
I have found a lot of articles on custom binding to a an object. Also, I found articles about "parameter binding", however those dealt with FromUri and FromBody. I didn't find anything that I felt had a direct parallel to what I'm facing.
You could achieve what you want by defining 3 different GET method with parameters matched with the query segment of the Url like the code snippet below:
public class ProductsController : ApiController
{
//Matched api/products?page=1
public IHttpActionResult Get(int page)
{
return GetPagedData(page);
}
//Matched api/products?paged=1
public IHttpActionResult GetPaged(int paged)
{
return GetPagedData(paged);
}
//Matched api/products?pagIndex=1
public IHttpActionResult GetPageIndex(int pageIndex)
{
return GetPagedData(pageIndex);
}
//Do the real paging here
private IHttpActionResult GetPagedData(int page =1)
{
return Ok("Data Pages");
}
}

Jquery postback not working on mvc 4 client side

I'm trying to simply create a json postback so I can update some controls on the client side. I cant find a good example to show this.
Here's what I got so far which appears to be firing off an alert from the controller but keeps saying 'undefined' object on client side.
What is best practice method of achieving this as I dont know how to debug javascript in the same manner as regular code? :( I'm using vs2012 express, mvc 4, jquery 1.7.1 and jquery mobile 1.1.
My controller Time/Index:
[HttpPost]
public JsonResult Index()
{
var msg = "hello there"; //test message
return Json(msg);
}
My client side:
function populateUserDetails() {
var user = {};
user.UserId = $("#UserId").val(); // potential fields i may use once i get it working
$.post('Time/Index', user, updateFields, 'json');
};
updateFields = function (data) {
alert("hi " + data.msg);
$("#textEntered").val(data.msg);
};
*** UPDATE *********
fixed it by wrapping returned object in controller into a temporary class:
[HttpPost]
public JsonResult Index()
{
var response = new {msg = "hello there"}; //here's what i changed
return Json(response);
}
Replace your last line of code as below.
return Json(response,JsonRequestBehavior.AllowGet);
so it should be like that
[HttpPost]
public JsonResult Index()
{
var response = new {msg = "hello there"};
//here's what i changed
return Json(response,JsonRequestBehavior.AllowGet);
}

How to unit test a custom actionresult

I'm trying to unit test a custom action result. I recently watched Jimmy Bogard's excellent MvcConf video ("put your controllers on a diet") http://www.viddler.com/explore/mvcconf/videos/1/ and have started to try and implement some custom action results. I've managed that without a problem, the ActionResult works fine at runtime but I'm having trouble trying to unit test them.
Unfortunately in the code download there are no unit tests for Jimmy's custom action methods... which make me wonder.
I realise that action methods just return instances of the ActionResult types and its the MVC framework that actually calls the ExecuteResult method, which of course is not available when running the unit test. So my unit test is now just creating an instance of my custom ActionResult and I then call ExecuteResult.
Unfortunatley in the ExecuteResult method of my custom ActionResult it is also calling the ExecuteResult method of a ViewResult that I passed it. At that point it blows up. How should I be mocking/stubbing these things to get my unit test working?
public class SendToAFriendActionResult : ActionResult
{
public const string INVALID_CAPTCHA = "You don't appear to have filled out the two words from the security image correctly to prove you're a human. Please try again.";
public const string INVALID_MODEL_STATE = "You don't appear to have filled out all the details correctly. Please try again.";
public const string CONTACT_FAIL = "Unfortunately we experiend a problem sending the link. Please try again later.";
public const string SEND_TO_A_FRIEND_FAIL_KEY = "ContactFail";
private RedirectResult _success;
private ViewResult _failure;
private readonly SendToAFriendModel _model;
private readonly bool _captchaValid;
private readonly MessageBuilderServiceBase _mbs;
public RedirectResult Success
{
get { return _success; }
set { _success = value; }
}
public ViewResult Failure
{
get { return _failure; }
set { _failure = value; }
}
public SendToAFriendActionResult(RedirectResult success, ViewResult failure, SendToAFriendModel model, bool captchaValid, MessageBuilderServiceBase mbs)
{
_success = success;
_failure = failure;
_model = model;
_captchaValid = captchaValid;
_mbs = mbs;
}
public override void ExecuteResult(ControllerContext context)
{
if (!_captchaValid)
{
Failure.TempData[SEND_TO_A_FRIEND_FAIL_KEY] = INVALID_CAPTCHA;
// On reaching this point I receive the error
// Object reference not set to an instance of an object
// as the MVC framework calls FindView
Failure.ExecuteResult(context);
return;
}
if (!context.Controller.ViewData.ModelState.IsValid)
{
Failure.TempData[SEND_TO_A_FRIEND_FAIL_KEY] = INVALID_MODEL_STATE;
Failure.ExecuteResult(context);
return;
}
_mbs.RecipientEmailAddress = _model.EmailRecipient;
_mbs.SendersName = _model.SendersName;
_mbs.Url = _model.URL;
var result = _mbs.sendMessage();
if (!result)
{
Failure.TempData[SEND_TO_A_FRIEND_FAIL_KEY] = CONTACT_FAIL;
Failure.ExecuteResult(context);
return;
}
Success.ExecuteResult(context);
}
}
Here's the start of my unit test ...
IMessageService _emailMessageSerivce;
IGalleryRepository _repository;
var stfModel = new SendToAFriendModel
{
SendersName = "Someone",
URL = "http://someurl.com",
EmailRecipient = "a-friend#somewherelse.com"
};
var failure = new ViewResult() {ViewName ="SendToFriend"};
const bool captchaValid = false;
var fakeControlllerContext = MockRepository.GenerateStub<ControllerContext>(null);
var stf = new SendToAFriendActionResult(null, failure, stfModel, captchaValid, null);
stf.ExecuteResult(fakeControlllerContext);
I've put comments in the SUT to show were the problem occurs.
I know I should be stubbing/mocking somehow but I just can't seem to resolve this.
From ASP.NET MVC 2 In Action (coauthored by Jimmy Bogard):
By taking that hard-to-test code out
of an action and putting it into the
Execute method of an action result,
you ensure that the actions become
significantly easier to unit-test.
That’s because when you unit-test an
action, you assert the type of action
result that the action returns and the
state of the action result. The
Execute method of the action result
isn’t executed as part of the unit
test.
Unit tests are designed to isolate behavior and concerns. You're mixing concerns by calling ExecuteResult from within your custom Action. Instead, I would have the SendToAFriendActionResult return the actual ActionResult (Failure or Success):
public ActionResult GetAction(..)
{
ActionResult result;
//logic here to determine which ActionResult to return
return result;
}
In your Controller:
public ViewResult SendToAFriend()
{
return SendToAFriendActionResult(null, failure, stfModel, captchaValid, null)
.GetAction();
}
This method will allow the MVC framework to do its job and isolates those concerns outside your custom ActionResult. Your test should assert that the correct type of Action, failure or success, is returned based on the parameters you set going in.

How to get and set http headers in an Action, the testable way

I have an action that returns either a FileContentResult or a NotModifiedResult, which is a custom result type that returns HTTP 304 to indicate that the requested resource has not been modified, like this:
[ReplaceMissingPicture(Picture = "~/Content/Images/nothumbnail.png", MimeType = "image/png")]
public ActionResult Thumbnail(int id)
{
var item = Service.GetItem(id);
var requestTag = Request.Headers["If-None-Match"] ?? string.Empty;
var tag = Convert.ToBase64String(item.Version.ToArray());
if (tag == requestTag)
{
return new NotModifiedResult();
}
if (item.Thumbnail != null)
{
var thumbnail = item.Thumbnail.ToArray();
var mime = item.PictureMime;
Response.AppendHeader("ETag", tag);
return File(thumbnail, mime);
}
else
{
return null;
}
}
This action needs to access the Response object, which is of course not present during testing, so that makes this action untestable. I could add conditional statements around it, so that it runs during testing, but then I can't test for the headers being set correctly.
What would be a solution to this problem?
FYI, the ReplaceMissingPicture filter returns a specific resource in case null was returned from this action, to keep the MapPath() call out of the controller for the very same reason.
The first step would be to create an interface which simplifies the services you need:-
public interface IHeaders
{
public string GetRequestHeader(string headerName);
public void AppendResponseHeader(string headerName, string headerValue);
}
Now create a default implementation:-
public Headers : IHeaders
{
public string GetRequestHeader(string headerName)
{
return HttpContext.Current.Request[headerName];
}
public void AppendResponseHeader(string headerName, string headerValue)
{
HttpContext.Current.Response.AppendHeader(headerName, headerValue);
}
}
Now add a new field to your Controller:-
private IHeaders myHeadersService;
add new constructor to you controller:-
public MyController(IHeaders headersService)
{
myHeadersService = headersService;
}
modify or add the default constructor:-
public MyController()
{
myHeadersService = new Headers();
}
now in your Action code use myHeadersService instead of the Response and Request objects.
In your tests create your own implementation of the IHeaders interface to emulate/test the Action code and pass that implementation when constructing the Controller.
How about creating a subclass of FileResult--say ETagFileResult--that in its ExecuteResult() method sets the ETag header, and then defaults to the base class implementation? You can test that class with a mocked context (as you presumably are with your NotModifiedResult) to be sure that it's doing the right thing. And remove the entire complication from the testing of the controller.
Failing that, it's possible to set a mocked context on the controller in your test (after instantiating the class, before calling the action method). See this question, for instance. But that seems like more work.
(Also, by the way, it looks like you're quoting the tag value twice there: once when tag is set, and once more when you actually set the header....)

Resources