I am trying to figure, how to call a specific function name in WepApi.
Currently if i call the WebApi with that structure api/{controllerName
its working (in case that the function name start with "get")
What i am trying to accomplish is that:
in JS
$http.get("http://localhost:34662/api/webapi/CustomfunctionName/")
.then(function (response) {
vm.employees = response.data;
}
in WebApi
[HttpGet]
[Route(Name = "CustomfunctionName")]
public IEnumerable<tblEmployees> CustomfunctionName()
{
using (Entities entities = new Entities())
{
return entities.tblEmployees.ToList();
}
}
I also tried to add a decorator above the function in the WebApi:
[Route(Name = "CustomfunctionName")]
but it didn't help.
How can it be done?
Could you add RoutePrefix attribute at the controller, and try again?
[RoutePrefix("api/webapi")]
public class WebApiController : ApiController
{
[HttpGet]
[Route("CustomfunctionName")]
public IEnumerable<tblEmployees> CustomfunctionName()
{
}
}
Solution per #E.Meir: If you use [ActionName(...)], you should decorate it to every action method inside the controller.
Related
I'm trying to call a .NET Core API from AngularJS. In the AngularJS I'm calling the method like this:
$http({
method: 'POST',
url: '/api/message/transaction/' + this.transaction.id,
data: { "transactionJson": "hello"}
})
.then(function (response) {
var r = response;
})
My .NET Core API method is like this:
[Route("~/api/message/transaction/{transactionId}")]
[HttpPost]
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] string transactionJson)
{
I'm getting a 400 Bad Request response back from the server. How do I fix it?
I realised the type for the parameter must be a type that has a property named TransactionJson, so I need to define a new C# type:
public class TransactionData() {
public string TransactionJson
}
Then in the API method:
[Route("~/api/message/transaction/{transactionId}")]
[HttpPost]
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] TransactionData transactionJson)
{
getting a 400 Bad Request response back from the server. How do I fix it?
To fix the issue, as your mentioned, one solution is modifying action parameter, like below.
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] TransactionData transactionJson)
{
//...
//code logic here
TransactionData class
public class TransactionData
{
public string TransactionJson { get; set; }
}
Besides, we can also implement and use a custom plain text input formatter to make PostTransaction action method that accepts a string-type ACTION parameter work well.
public class TextPlainInputFormatter : TextInputFormatter
{
public TextPlainInputFormatter()
{
SupportedMediaTypes.Add("text/plain");
SupportedEncodings.Add(UTF8EncodingWithoutBOM);
SupportedEncodings.Add(UTF16EncodingLittleEndian);
}
protected override bool CanReadType(Type type)
{
return type == typeof(string);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
string data = null;
using (var streamReader = new StreamReader(context.HttpContext.Request.Body))
{
data = await streamReader.ReadToEndAsync();
}
return InputFormatterResult.Success(data);
}
}
Add custom formatter support
services.AddControllers(opt => opt.InputFormatters.Insert(0, new TextPlainInputFormatter()));
Test Result
I am trying to pass complex object from angular service to MVC controller. Below is the code-:
Angular Controller
$scope.saveData = function () {
var resultData = new Object();
resultData.Name = $scope.Name;
resultData.Address = new Object();
resultData.Address = $scope.Address;
resultData.Address.Contact = $scope.Address.Contact;
var promiseOrganization = AngularService.saveResult(resultData);
promiseOrganization.then(function (result)
{
alert("Saved successfully.");
}
)
}
Angular Service
this.saveResult = function (resultData) {
return $http.post("/Form/SaveData/" + resultData);
}
MVC Controller
[System.Web.Http.HttpPost]
public string SaveData([FromBody] resultData data)
{
//operation to perform
return "Data Reached";
}
When I try passing complex object from Angular service to mvc controller. It gives me null i.e. object becomes null.
Please suggest.
When using the $http.post method you need to pass the data object as the second paramenter. You can read up on it here
So your angular code should look like
$http.post("/Form/SaveData/", data);
You then need a server side representation of the data you are passing the WebApi controller
public class MyCustomObject
{
public string Name { get; set; }
public MyCustomAddress Address { get; set; }
}
public class MyCustomAddress
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Contact { get; set; }
}
You need to update your WebApi controller code to use the new server side class as the parameter. Note that I am not using the [FromBody] attribute as this link explains you only need to use the [FromBody] attribute when you want to force Web API to read a simple type from the request body(your type is a complex type)
To force Web API to read a simple type from the request body, add the [FromBody] attribute to the parameter
Updated WebApi Controller code without the [FromBody] attribute:
[System.Web.Http.HttpPost]
public string SaveData(MyCustomObject data)
{
//operation to perform
return "Data Reached";
}
Change your post function to something like this,
$http.post('/Form/SaveData/', resultData)
.success(function (data, status, headers, config) {
})
.error(function (data, status, headers, config) {
});
You are wrong in your post command. It should be:
$http.post("/Form/SaveData/",{resultData: resultData});
The problem is you need to add the following header -> 'Content-Type': 'application/x-www-form-urlencoded'
$http.post('/Form/SaveData/', resultData, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}});
I have the following method in an asp.net MVC controller, which my angular code is trying to call:
[HttpPost]
public JsonResult SaveEducationList(List<InventoryGroupModel> inventoryEduList, int examId)
{
var listOfInventories = _examService.AddEduInventoryGroup(inventoryEduList);
return Json(listOfInventories);
}
My angular code to call this is:
saveEduList: function (inventoryEduList, examId) {
return $resource('/mysite/Setup/SaveEducationList',
{ inventoryEduList: '#inventoryEduList', examId: '#examId' }, {
save: {
method: 'POST',
isArray: true
}
}).save(inventoryEduList, examId);
}
When this angular method is called, I can see in Chrome's debugger that both the inventoryEduList and examId are populated, but whenever the call to the MVC method is made, nothing happens. Fiddler shows that it was calling method just passing in the examId, nothing else. Is there anyway to pass both parameters?
Try following...
create a new class
public class SaveParam {
public List<InventoryGroupModel> InventoryEduList {get;set;}
public int ExamId {get;set;}
}
then
[HttpPost]
public JsonResult SaveEducationList(SaveParam param)
{
var listOfInventories = _examService.AddEduInventoryGroup(param.InventoryEduList );
return Json(listOfInventories);
}
hope this help
I am just learning on how to use Web API with angular but I am having a few issues on retrieving data and I would appreciate it if someone could help me.
I have a controller called GetUserController with the following methods.
public class GetUserController : ApiController
{
[HttpGet]
public string GetUserName()
{
var user = "John Doe"
return user;
}
[HttpGet]
public string GetUserName2()
{
string user = "Jane Doe";
return user;
}
}
//Angular side of things
function getUser() {
return $http.get('/api/GetUser').then(function (data) {
return data;
});
}
The above code works fine and and returns the first user from the controller . however when I try to get the second by using the below angular code:
function getUser() {
return $http.get('/api/GetUser/GetUserName2').then(function (data) {
return data;
});
}
This does not work for some reason it says it can't find the GetUserName2 method. Am I missing something ? Please help?
EDIT: The error i'm getting is : Multiple actions were found that match the request
As #shammelburg has pointed out, this is as a result of Web.API not being able to match your request to a controller/method.
It's not so much that it's not RESTful, and has nothing to do with the verb you are using... it's just that an appropriate route map was not found.
Per the accepted answer, you can add another generic route map to enable the method of access you are attempting, however a more specific option exists using attribute routing:-
public class GetUserController : ApiController
{
[Route("api/getuser")]
[HttpGet]
public string GetUserName()
{
var user = "John Doe"
return user;
}
[Route("api/getuser/getusername2")]
[HttpGet]
public string GetUserName2()
{
string user = "Jane Doe";
return user;
}
}
And to enable the use of attribute routes, add this to your WebApiConfig class:-
config.MapHttpAttributeRoutes();
This method allows you to setup specific custom mappings of URLs to controllers/methods at the individual method level, without having to make a global route map that may conflict with something else in your application at a later date.
You can find more info on attribute routing here
Whilst the above will resolve the specific issue you are having, there would in practice be a different way to implement the example you gave:-
public class GetUserController : ApiController
{
[Route("api/user/{id}")]
[HttpGet]
public string GetUserName(int id)
{
// this would be replaced with some sort of data lookup...
var user = "unknown";
if (id == 1) {
user = "John Doe";
} else if (id == 2) {
user = "Jane Doe";
} // and so on...
return user;
}
}
In the above, the URL api/user/x where x is a number, e.g. api/user/1 will match the GetUserName method of the GetUserController and pass the number as an argument to the method.
This would be accessed using something like this in Angular:-
function getUser(id) {
return $http.get('/api/user/' + id).then(function (data) {
return data;
});
}
This is caused because it is not a true RESTful call which use HTTP verbs, GET, POST, PUT, DELETE.
The way to get your code to work is by altering your WebApiConfig.cs file.
From:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
To:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
As you can see we've added the {action} to the routeTemplate which makes this very much like a MVC Controller.
This allows you to call your API methods (GetUserName & GetUserName2) name like you are trying to do in your angular $http function.
Example:
return $http.get('/api/GetUser/GetUserName')
return $http.get('/api/GetUser/GetUserName2')
if i have this class:
public class MainMenuModel
{
public MainMenuModel(string transKey, string stateName, string displayUrl, bool hasSubMenu= false,List<SubMenuModel>subMenu=null)
{
TransKey = transKey;
StateName = stateName;
DisplayUrl = displayUrl;
HasSubMenu = hasSubMenu;
SubMenu = subMenu;
}
public string TransKey { get; set; }
public string StateName { get; set; }
public string DisplayUrl { get; set; }
public bool HasSubMenu { get; set; }
public List<SubMenuModel>SubMenu { get; set; }
}
And if i populate that class like this:
MainMenu.Add(new MainMenuModel("MY_TICKETS", "account.tickets", "/account/tickets/"));
MainMenu.Add(new MainMenuModel("TRANSACTION_HISTORY", "account.transactionhistory", "/account/transactions"));
MainMenu.Add(new MainMenuModel("PAYIN","account.payin","/account/payin"));
MainMenu.Add(new MainMenuModel("PAYOUT", "account.payout", "/account/payout"));
MainMenu.Add(new MainMenuModel("TICKET_PAYOUT", "account.ticketpayout", "/account/ticketpayout"));
MainMenu.Add(new MainMenuModel("SETTINGS","default","default",true,
new List<SubMenuModel>(){
new SubMenuModel("PERSONAL_INFORMATION","account.personalinformation","/account/personalinformation"),
new SubMenuModel("NOTIFICATIONS","account.notificationsettings","/account/notifications"),
new SubMenuModel("CHANGE_PASSWORD","account.changepassword","/account/passwordchange"),
new SubMenuModel("GAME_SETTINGS","default","default"),
}));
MainMenu.Add(new MainMenuModel("PROMOTIONS", "default", "default", true,
new List<SubMenuModel>(){
new SubMenuModel("BONUSES","default","default"),
new SubMenuModel("COMPETITIONS","default","default"),
new SubMenuModel("VOUCHER_REDEEM","default","default"),
}));
How can i call this in angular ..and pass it to $scope.something?Any suggestion?
If you need forming page on server - try to serialize this collection and put in on angular controller init
<div ng-controller="SomeController" ng-init="initialize('#Model.ToJson()')">
My recommendation is that you setup WebApi along with your existing ASP.NET MVC layer.
With that being said all you need to do is to implement the Rest services as GETs or POSTs and from your angular a simple invoke with $http :
Server Side
Using Microsoft Web Api Controller class "ValuesController" but it can be any class name which looks like this:
public class ValuesController : ApiController
{
public string Get(int id){ return "value"; }
...
Client Side
In my AngularJS Controller function it gets the value using $http service:
$http({method:'GET',url: '/api/values/1'}).success(function(data){
$scope.value =data;
})
First, you'll need to setup a server endpoint you can reach through ajax, that'll return the MainMenu structure as a JSON response.
Once you have that endpoint setup, there are several ways to get this data into angular, although I think the best way is to create an Angular service to manage this data. Something like this (bear with me, since I don't know the particulars of your project):
angular.module('application').factory('mainMenuService', ['$http', function($http) {
var ServiceInstance = {
_menuItems: [],
_fetchMenuItems: function() {
var self = this;
$http.post('your/server/endpoint').success(function(data, status, headers, config) {
// Clear exisiting items
self._menuItems.length = 0;
// Assuming menu items have been returned as JSON structure
// Add them all into the Service's mainMenu cache
self._menuItems.push.apply( self._menuItems, data.menuItems );
});
},
getMenuItems: function() {
if (!this._menuItems.length) {
this._fetchMenuItems();
}
// No need to wait on async operation because we're using the same array instance,
// and angular will observe this instance and detect when new items are added.
return this._menuItems;
}
};
return ServiceInstance;
}]);
Then, in your Angular controllers use the service:
// Notice how we reference the 'mainMenuService' here, and angular will inject it automatically
angular.module('application').controller('mainMenuController', ['mainMenuService', function (mainMenuService) {
$scope.mainMenuItems = mainMenuSevice.getMenuItems();
}]);
That way you'll decouple the data from the controller, and you can reuse the service in any controller where it's needed.