对于想了解如何将错误呈现给客户端?AngularJS/WebApi模型状态的读者,本文将是一篇不可错过的文章,我们将详细介绍错误怎么描述,并且为您提供关于AngularJs-.netMVCWebApi
对于想了解如何将错误呈现给客户端?AngularJS / WebApi模型状态的读者,本文将是一篇不可错过的文章,我们将详细介绍错误怎么描述,并且为您提供关于AngularJs -.net MVC WebApi身份验证示例、angularjs – Angular JS MVC Web API模型/参数不绑定.NET Core、angularjs – Angular POST to Web API不传递数据、angularjs – Angular2到REST WebApi CORS问题的有价值信息。
本文目录一览:- 如何将错误呈现给客户端?AngularJS / WebApi模型状态(错误怎么描述)
- AngularJs -.net MVC WebApi身份验证示例
- angularjs – Angular JS MVC Web API模型/参数不绑定.NET Core
- angularjs – Angular POST to Web API不传递数据
- angularjs – Angular2到REST WebApi CORS问题
如何将错误呈现给客户端?AngularJS / WebApi模型状态(错误怎么描述)
我正在使用WebApi为后端构建AngularJS
SPA应用程序。我在服务器上使用属性进行模型验证,如果验证失败,这就是我从ModelState返回的内容。
{"Message":"The request is invalid.","ModelState":{"model.LastName":["Last Name must be at least 2 characters long."]}}
然后如何使用AngularJS将其呈现给客户端?
//Save User Info $scope.processDriverForm = function(isValid) { if (isValid) { //set button disabled, icon, text $scope.locked = true; $scope.icon = ''fa fa-spinner fa-spin''; $scope.buttonText = ''Saving...''; $scope.submitted = true; $scope.formData.birthDate = $scope.formData.birthMonth + ''/'' + $scope.formData.birthDay + ''/'' + $scope.formData.birthYear; $http({ method: ''POST'', url: ''api/Account/Register'', data: $.param($scope.formData), headers: { ''Content-Type'': ''application/x-www-form-urlencoded'' } // set the headers so angular passing info as form data (not request payload) }) .success(function (data) { console.log(data); toastr.success(''User '' + $scope.formData.username + '' created!''); $scope.userForm.$setPristine(); $scope.formData = {}; //reset the button $scope.locked = false; $scope.icon = ''''; $scope.buttonText = ''Save''; //reset validation submitted $scope.submitted = false; }) .error(function (data, response) { console.log(data); toastr.error(''Ooops! There was an error creating the user. Try again and if the problem persists, contact Support.''); //reset the button $scope.locked = false; $scope.icon = ''''; $scope.buttonText = ''Save''; $scope.submitted = false; var resp = {}; var errors = []; for (var key in resp.ModelState) { for (var i = 0; i < resp.ModelState[key].length; i++) { errors.push(resp.ModelState[key][i]); } } $scope.errors = errors; }); } else { toastr.warning(''Invalid User Form, correct errors and try again.''); } };
答案1
小编典典呼叫服务器时,请根据对$http
诺言的拒绝捕获错误。
然后在您的控制器中,我建议在处理显示的错误时将对错误数组的响应展平,如下面的小提琴示例所示:
for (var key in resp.ModelState) { for (var i = 0; i < resp.ModelState[key].length; i++) { errors.push(resp.ModelState[key][i]); }}
放在一起:
// Post the data to the web api/service$http.post(url, data) .success(successHandler) .error(function (response) { // when there''s an error, parse the error // and set it to the scope (for binding) $scope.errors = parseErrors(response); });//separate method for parsing errors into a single flat arrayfunction parseErrors(response) { var errors = []; for (var key in response.ModelState) { for (var i = 0; i < response.ModelState[key].length; i++) { errors.push(response.ModelState[key][i]); } } return errors;}
AngularJs -.net MVC WebApi身份验证示例
我不知道该怎么做是在我的$资源中设置角度的标题中传递此信息(用户/通行证).有没有完整的例子可以更好地告诉我如何做到这一点?我知道它涉及cookie并使用服务器传回的令牌,但我不知道如何将各个部分放在一起.
当我把所有这些结合在一起时,我希望通过所有层(DAL,RESTFUL,控制台测试层)发布一个完整的骨架示例.
所以问题是 – 在使用AngularJS $资源时,如何将身份验证信息插入客户端的标头中?
谢谢
如果你想在Header中传递令牌而不是在Angular端的cxookie中传递令牌,请执行以下操作:$httpProvider.defaults.headers.common [‘X-Auth’] = yourKey;在您的配置块中.
然后,如果您想知道用户是否已登录,或者他是否拥有权限,则只需实现拦截器.这是一个简单的工厂,你会在你的配置块中推送响应者.
该工厂将监听来自服务器的每个响应,并且在他的实现中,您将检查错误情况下响应的状态代码:
401 – >没有记录
403 – >没有授权
工厂的例子:
myModule.factory('myHttpInterceptor',function ($q) { return function (promise) { return promise.then(function (response) { // do something on success return response; },function (response) { // do something on error //check status 401 or 403 return $q.reject(response); }); }; });
然后把你的工厂放在你的con fig块中的http responseIntercetors中:
myModule.config(function ($httpProvider) { $httpProvider.responseInterceptors.push('myHttpInterceptor'); });
请记住,AngularJS 1.1.4中不推荐使用此解决方案(仍然不稳定)……
工厂必须有所不同,请参阅这篇文章了解更多信息:AngularJS Intercept all $http JSON responses
希望能帮助到你
angularjs – Angular JS MVC Web API模型/参数不绑定.NET Core
我有一个apiService来处理对服务器的所有POST和GET请求,如下所示:
module TBApp { export class apiService { static $inject = ['$http','notificationService']; constructor(private $http,private notificationService: notificationService) { } get(url,config,success,failure) { return this.$http.get(url,config) .then(result => { this.handleResponse(result,success); },result => { this.handleError(result,failure) }); } post(url,data,failure) { return this.$http.post(url,data) .then(result => { this.handleResponse(result,failure) }); } handleResponse(result,success) { alert('success'); success(result); } handleError(result,failure) { if (result.status === '401') { this.notificationService.displayError('Authentication required.'); //this.$rootScope.prevIoUsstate = this.$location.path(); //this.$location.path('/login'); } else if (failure !== null) { failure(result); } } } }
现在,当我发送此请求时:
onCompanyChanged(selectedCompany,model,companyName) { this.apiService.post('/api/Dashboard/GetAssetListByCompany',{ companyId: selectedCompany.id },response => { this.assetListviewmodel = response.data.data; },response => { this.notificationService.displayError(response.data.message); }); }
它没有绑定控制器中的companyId
这是控制器:
[Route("api/[controller]")] public class DashboardController : BaseController { [HttpPost] [Route("GetAssetListByCompany")] public IActionResult GetAssetListByCompany([FromBody]int companyId) { return CreateJsonResult(() => { if (companyId == 0) { return new xPTJsonResult(null,xPTStatusCodesEnum.Success,"Company Id is 0"); } //var treeModel = _dashboardProvider.GetTreeModelByCompany(companyId,usermodel); return new xPTJsonResult(null,"Loaded assets successfully"); }); } }
即使我在浏览器中检查了请求,也表明companyId在Payload中.
NOTE: The same function works when I post a viewmodel
编辑
在上面的场景中,我只将一个参数传递给控制器,但在某些情况下,我希望能够在不使用viewmodel的情况下传递2或3个参数.
例如
public IActionResult GetAssetListByCompany([FromBody]int companyId,[FromBody]int assetId) {....
要么
public IActionResult GetAssetListByCompany([FromBody]int companyId,[FromBody]int assetId,[FromBody]bool canEdit = false) {.....
然后在客户端我可以这样做:
this.apiService.post('/api/Dashboard/GetAssetListByCompany',{ companyId: selectedCompany.id,assetId: 123 }.....
要么
this.apiService.post('/api/Dashboard/GetAssetListByCompany',canEdit: true,assetId: 22 }....
解决方法
MVC改变了
有关各种选项,请参阅Model Binding,此处的最佳方法是基于查询字符串进行绑定,因为您只需要一个基本类型.如果您有一个基本类型数组仍然可以绑定到查询字符串,则查询字符串变量名称将为每个值重复一次.
因此,我们所做的唯一更改是指定参数来自查询字符串,并且它与Http Get请求而不是Post相关联.
[Route("api/[controller]")] public class DashboardController : BaseController { [HttpGet] // change to HttpGet [Route("GetAssetListByCompany")] public IActionResult GetAssetListByCompany([FromQuery]int companyId) // use FromQuery { return CreateJsonResult(() => { if (companyId == 0) { return new xPTJsonResult(null,"Company Id is 0"); } //var treeModel = _dashboardProvider.GetTreeModelByCompany(companyId,usermodel); return new xPTJsonResult(null,"Loaded assets successfully"); }); } }
AngularJS发生了变化
我们扩展apiService以允许使用HttpGet传递调用数据.这可以使用params on the $http call完成,它将使用名称作为查询字符串值名称和值作为值部分,根据传入的数据动态创建URL.
export class apiService { /* all other code is left as is,just change the get method to also accept data via the params. If null is passed in then it is ignored. */ get(url,failure) { return this.$http({ url: url,config: config,params: data,method: "GET" }) .then(result => { this.handleResponse(result,failure) }); } }
在通话中我们只需要从post更改为get,它应该可以工作.
// only change from post to get onCompanyChanged(selectedCompany,companyName) { this.apiService.get('/api/Dashboard/GetAssetListByCompany',response => { this.assetListviewmodel = response.data.data; },response => { this.notificationService.displayError(response.data.message); }); }
编辑 – 这很灵活
更重要的是,这种设计在角度方面是灵活的.如果您扩展MVC操作或具有采取其他参数的各种操作,则无需执行任何其他更改即可运行.例:
[HttpGet] [Route("GetSomethingElseFromServer")] public IActionResult GetSomethingElseFromServer([FromQuery]int companyId,[FromQuery]string assetName,[FromQuery]string companyModelNumber) // use FromQuery
对你的角度api的调用将是
this.apiService.get('/api/Dashboard/GetSomethingElseFromServer',{ companyId: companyId,assetName: somePassedInAssetNameVar,companyModelNumber: somePassedInModelNumber }
编辑 – 您也可以发送数组
要回答关于如何将多个基元类型作为数组发送的问题,您可以这样做.同样,这假设它不是您要发送的复杂类型,但是,例如,公司ID列表.
c#代码
[HttpGet] [Route("GetAssetListByCompany")] public IActionResult GetAssetListByCompany([FromQuery]int[] companyIds) // use an array of int ie. int[]. i changed the variable name to make it clear there can be more than 1
Angular调用,注意没有必要更改服务
onCompanyChanged(selectedCompany,{ "companyIds[]": [id1,id2,id3] },// note the name is Now enclosed in quotes,made plural,and includes []. The value is an array response => { this.assetListviewmodel = response.data.data; },response => { this.notificationService.displayError(response.data.message); }); }
编辑 – 如果你想要POST
您目前只发送一个原始字段,因此POST中的MVC框架无法正确反序列化.您需要将参数包装在视图模型中,将其作为查询字符串部分发送,或将其作为表单字段值发送.这是带有查询字符串部分的POST,它可以正常工作.
选项1
将其附加到URL
[HttpPost] // change to HttpGet [Route("GetAssetListByCompany")] public IActionResult GetAssetListByCompany([FromQuery] int companyId) // use FromQuery
角度呼叫
this.apiService.post('/api/Dashboard/GetAssetListByCompany/?companyId=' + selectedCompany.id +,null,// the rest of the code remains unchanged so I did not include it
选项2
扩展apiService以获取params对象,以便它可以构建您的查询.无论哪种方式,你都会遇到调用者不得不对http调用有所了解.
this.apiService.post('/api/Dashboard/GetAssetListByCompany',{companyId: selectedCompany.id},// the rest of the code remains unchanged so I did not include it post(url,params,failure) { return this.$http({ url: url,data: data,params: params,method: "POST" }) .then(result => { this.handleResponse(result,failure) }); }
选项3
更新视图模型以采用复杂类型,这不需要更改角度代码.
public class ListByCompanyModel { public int CompanyId {get;set;} } [HttpPost] // change to HttpGet [Route("GetAssetListByCompany")] public IActionResult GetAssetListByCompany([FromBody] ListByCompanyModel model) // use FromQuery
angularjs – Angular POST to Web API不传递数据
我正在发布一个方法,该方法将返回系统中实体的一些搜索结果.它看起来像这样:
public IEnumerable<dynamic> Post(string entity,FormDataCollection parameters) { // entity is passed on the route. // parameters contains all the stuff I'm trying to get here. }
如果我使用jQuery.post调用该方法:
$.post('api/search/child',{where : 'ParentID = 1'},function(d){ foo = d });
它运作正常,并返回我期望的.
我在我的角度应用程序中提供了一个类似的调用服务:
$http.post('api/search/child',{ where: 'parentID = ' + parent.ID }) .success(function (data,status,headers,config) { // etc. })
但是当它在服务器上点击我的“Post”方法时,“paramters”为空.
经过一些谷歌搜索后,我尝试添加一个内容类型的标题,以确保它作为JSON传递,并尝试JSON.stringify-ing和$.param() – “数据”参数,但没有做任何事情(和从我所读到的那些不应该是必要的.)我在这里做错了什么?谢谢你的帮助!
更新:
这是来自(工作)jQuery示例的原始请求:
POST http://localhost:51383/api/search/child HTTP/1.1 Accept: */* Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Referer: http://localhost:51383/mypage.aspx Accept-Language: en-US Accept-Encoding: gzip,deflate User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko Host: localhost:51383 Content-Length: 23 DNT: 1 Connection: Keep-Alive Pragma: no-cache Cookie: (etc) Authorization: (etc) where=ParentID+%3D+1
来自(失败的)Angular样本的原始请求:
POST http://localhost:51383/api/search/parent HTTP/1.1 Content-Type: application/json;charset=utf-8 Accept: application/json,text/plain,*/* Referer: http://localhost:51383/mypage.aspx Accept-Language: en-US Accept-Encoding: gzip,deflate User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko Connection: Keep-Alive Content-Length: 27 DNT: 1 Host: localhost:51383 Pragma: no-cache Cookie: (etc) {"where":"scorecardID = 1"}
很奇怪.即使我将’json’数据类型参数添加到jQuery调用的末尾,它仍然会创建www-form-urlencoded请求.那是有效的.我的Web API应用程序已经为JSON设置(但感谢Dalorzo).
解决方法
System.Web.Http.GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); config.Formatters.Insert(0,new System.Net.Http.Formatting.JsonMediaTypeFormatter());
只有设置了正确的格式化程序,Content-Type = application / json才有效.
您也可以尝试在参数类型旁边使用[FromBody].
angularjs – Angular2到REST WebApi CORS问题
webapi启用CORS
var cors = new EnableCorsAttribute("*","*","*"); GlobalConfiguration.Configuration.EnableCors(cors);
它的作品,因为我有不同的网站(jquery / javascript)使用这个api.但是对于角度2,它不会.我收到以下消息:
Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
也许与“预检要求”有关?
谢谢你的帮助.
马科斯
如已经说明的那样,问题在于,在客户端发出的每个请求都将预检要求发送到服务器之前.
这种请求有一个OPTIONS类型,服务器有责任发送状态为200的预检应答,并设置接收来自该客户端的请求的头文件.
这是我的解决方案(带快递):
// Domain you wish to allow res.setHeader('Access-Control-Allow-Origin','http://localhost:3000'); // Request methods you wish to allow res.setHeader('Access-Control-Allow-Methods','GET,POST,PUT,DELETE'); // Request headers you wish to allow res.setHeader('Access-Control-Allow-Headers','YOUR-CUSTOM-HEADERS-HERE'); // Set to true if you need the website to include cookies in requests res.setHeader('Access-Control-Allow-Credentials',true); // Check if preflight request if (req.method === 'OPTIONS') { res.status(200); res.end(); } else { // Pass to next layer of middleware next(); }
如您所见,我设置标题,然后如果请求类型为OPTIONS,则提取.在这种情况下,我发回状态200并结束响应.
以这种方式,客户端将被授权,您还可以在所有请求中设置自定义标头.
关于如何将错误呈现给客户端?AngularJS / WebApi模型状态和错误怎么描述的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于AngularJs -.net MVC WebApi身份验证示例、angularjs – Angular JS MVC Web API模型/参数不绑定.NET Core、angularjs – Angular POST to Web API不传递数据、angularjs – Angular2到REST WebApi CORS问题的相关信息,请在本站寻找。
本文标签: