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
Related
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
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
I get error "The parameter 'wheels' is of Edm type kind 'Collection'.
You cannot call CreateCollectionWriter on a parameter that is not of
Edm type kind 'Collection'."
Below are details of my setup:
Web API 2.2 OData v4 service : I have defined Action in WheelsController class in my service like this:
public async Task<IHttpActionResult> UpdateWheels(ODataActionParameters parameters)
{
object value;
parameters.TryGetValue("carId", out value);
int carId= (int)value;
parameters.TryGetValue("wheels", out value)
IEnumerable<Wheel> wheels = (IEnumerable<Wheel>)value;
// logic goes here....
return OK();
}
In WebApiConfig.cs files, the Action configuration is defined as below:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Car>("Cars");
builder.EntitySet<Wheel>("Wheels");
var action = builder.EntityType<Wheel>().Collection.Action("UpdateWheels");
action.Parameter<int>("carId");
action.CollectionParameter<Wheel>("wheels");
I get success in invoking the above action from RESTClient extenstion in FireFox browser as POST request to URL "http://localhost/Service/Wheels/UpdateWheels" with Request Body as
{"carId":2,
"wheels":[{"Id":1,"Name":"Wheel Front 1","Description":"Front wheel left", "PositionEnum":"FrontLeft"},
{"Id":2,"Name":"Wheel Front 2","Description":"Front wheel right", "PositionEnum":"FrontRight"}]
}
However, it gives error when I try to invoke the above service action using Simple.OData.Client in client application such as
public async void TestUpdateWheels(List<Wheel> wheelList)
{
// client is derived from ODataClient from assembly Simple.OData.Client.Core.dll, v4.3.0.0
await client.For<Wheel>()
.Action("UpdateWheels")
.Set(new { carId = 2, wheels = wheelList})
.ExecuteAsync();
}
Error message: The parameter 'wheels' is of Edm type kind
'Collection'. You cannot call CreateCollectionWriter on a parameter
that is not of Edm type kind 'Collection'.
How can I call successfully the above Action from ODataClient?
This turn out to be a bug in Simple.OData.Client version 4.3.0 when I reported to the project site. For details, visit the link https://github.com/object/Simple.OData.Client/issues/117
The new bug fix version 4.7.2 of Simple.OData.Client has fixed the
issue for me!
Try out in this way. It works for me in one of my project.
public async Task<string> TestUpdateWheels(List<Wheel> wheelList)
{
string getRules = await client.ExecuteActionAsScalarAsync<string>
("UpdateWheels", new Dictionary<string, object>
{
{ "YourParamater", wheelList}
});
return getRules ;
}
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);
}
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;
}