[英]Generating a JS-client based on a ASP.NET WebAPI Controller
In modern web-projects that use RESTful API's we often see AJAX-calls like the one below littered around our JavaScript-files. 在使用RESTful API的现代Web项目中,我们经常会看到AJAX调用,就像下面的JavaScript文件一样。
$.ajax({
type: "POST",
url: myapp.baseUrl + 'Api/Note',
data: ko.mapping.toJSON(note),
contentType: 'application/json',
}).done(function (response) {
// do something
}).fail(function (jqxhr) {
// do something else
});
I love WebAPI, I love Knockout and I love tying the two together. 我喜欢WebAPI,我喜欢Knockout,我喜欢将两者结合在一起。 However these AJAX-calls are quite verbose and contain all kinds of details that I am not really interested in. So instead, I create a wrapper around these methods:
然而,这些AJAX调用非常冗长,包含了我并不感兴趣的各种细节。相反,我创建了一个围绕这些方法的包装器:
myapp.api.saveNote(note)
However this still requires me to actually write a wrapper containing the AJAX-call. 但是,这仍然需要我实际编写一个包含AJAX调用的包装器。 I was wondering if you could actually generate these wrappers .
我想知道你是否真的可以生成这些包装器 。 In essence, I would be generating a JS-based client for my WebAPI, similar to how Java and .NET can generate clients based on WSDL's.
本质上,我将为我的WebAPI生成一个基于JS的客户端,类似于Java和.NET如何基于WSDL生成客户端。
I've already looked at amplifyJS but this only partially solves the problem. 我已经看过amplifyJS,但这只能部分地解决问题。 I am looking for a solution that actually creates an interface based on the WebAPI-controllers in my solution.
我正在寻找一种解决方案,它实际上在我的解决方案中基于WebAPI控制器创建了一个接口。 If this does not exist, I will start tinkering myself.
如果这不存在,我会开始修补自己。 I've already got an idea for a
WebAPIClientGenerator
that uses reflection to iterate over all ApiController
's. 我已经有了一个
WebAPIClientGenerator
的想法,它使用反射迭代所有的ApiController
。
Just found a project called: ProxyApi 刚刚找到一个叫做ProxyApi的项目
ProxyApi is a library that automatically creates JavaScript proxy objects for your ASP.NET MVC and WebApi Controllers.ProxyApi是一个自动为ASP.NET MVC和WebApi控制器创建JavaScript代理对象的库。
GitHub: https://github.com/stevegreatrex/ProxyApi GitHub: https : //github.com/stevegreatrex/ProxyApi
Blog: http://blog.greatrexpectations.com/2012/11/06/proxyapi-automatic-javascript-proxies-for-webapi-and-mvc/ 博客: http : //blog.greatrexpectations.com/2012/11/06/proxyapi-automatic-javascript-proxies-for-webapi-and-mvc/
ProxyApi generated invalid JavaScript for my solution which contained over a hundred separate WebAPI actions. ProxyApi为我的解决方案生成了无效的JavaScript,其中包含一百多个单独的WebAPI操作。 This is probably because ProxyApi does not cover all WebApi features such as custom ActionName attributes.
这可能是因为ProxyApi未涵盖所有WebApi功能,例如自定义ActionName属性。 Moreover the ProxyApi library is a bit on the bulky side to my taste.
此外,ProxyApi库对我来说有点笨重。 There has to be a more efficient way to do this...
必须有一种更有效的方法来做到这一点......
So I decided to take a look at the ASP.NET WebAPI source code and it turns out WebAPI has self-describing functionality built into it. 所以我决定看一下ASP.NET WebAPI源代码,结果发现WebAPI内置了自我描述功能。 You can use the following code from anywhere in your ASP.NET solution to access WebAPI metadata:
您可以从ASP.NET解决方案的任何位置使用以下代码来访问WebAPI元数据:
var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();
Based on the output from apiExplorer.ApiDescriptions
, I rolled my own metadata provider: 根据
apiExplorer.ApiDescriptions
的输出,我推出了自己的元数据提供程序:
public class MetadataController : Controller { public virtual PartialViewResult WebApiDescription() { var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer(); var apiMethods = apiExplorer.ApiDescriptions.Select(ad => new ApiMethodModel(ad)).ToList(); return PartialView(apiMethods); } public class ApiMethodModel { public string Method { get; set; } public string Url { get; set; } public string ControllerName { get; set; } public string ActionName { get; set; } public IEnumerable<ApiParameterModel> Parameters { get; set; } public ApiMethodModel(ApiDescription apiDescription) { Method = apiDescription.HttpMethod.Method; Url = apiDescription.RelativePath; ControllerName = apiDescription.ActionDescriptor.ControllerDescriptor.ControllerName; ActionName = apiDescription.ActionDescriptor.ActionName; Parameters = apiDescription.ParameterDescriptions.Select(pd => new ApiParameterModel(pd)); } } public class ApiParameterModel { public string Name { get; set; } public bool IsUriParameter { get; set; } public ApiParameterModel(ApiParameterDescription apiParameterDescription) { Name = apiParameterDescription.Name; IsUriParameter = apiParameterDescription.Source == ApiParameterSource.FromUri; } } }
Use this controller in conjunction with the following view: 将此控制器与以下视图结合使用:
@model IEnumerable<Awesome.Controllers.MetadataController.ApiMethodModel> <script type="text/javascript"> var awesome = awesome || {}; awesome.api = { metadata: @Html.Raw(Json.Encode(Model)) }; $.each(awesome.api.metadata, function (i, action) { if (!awesome.api[action.ControllerName]) { awesome.api[action.ControllerName] = {}; } awesome.api[action.ControllerName][action.ActionName] = function (parameters) { var url = '/' + action.Url; var data; $.each(action.Parameters, function (j, parameter) { if (parameters[parameter.Name] === undefined) { console.log('Missing parameter: ' + parameter.Name + ' for API: ' + action.ControllerName + '/' + action.ActionName); } else if (parameter.IsUriParameter) { url = url.replace("{" + parameter.Name + "}", parameters[parameter.Name]); } else if (data === undefined) { data = parameters[parameter.Name]; } else { console.log('Detected multiple body-parameters for API: ' + action.ControllerName + '/' + action.ActionName); } }); return $.ajax({ type: action.Method, url: url, data: data, contentType: 'application/json' }); }; }); </script>
The controller will use the ApiExplorer
to generate metadata about all available WebAPI actions. 控制器将使用
ApiExplorer
生成有关所有可用WebAPI操作的元数据。 The view will render this data as JSON and then execute some JavaScript to transform this data to actual executable JavaScript functions. 该视图将此数据呈现为JSON,然后执行一些JavaScript以将此数据转换为实际的可执行JavaScript函数。
To use this little bit of magic, insert the following line in the head of your Layout page after your jQuery reference. 要使用这一点魔力,请在 jQuery引用之后在Layout页面的头部插入以下行。
@Html.Action(MVC.Metadata.WebApiDescription())
From now on, you can make your WebAPI calls look like this: 从现在开始,您可以使WebAPI调用如下所示:
// GET: /Api/Notes?id={id} awesome.api.Notes.Get({ id: id }).done(function () { // .. do something cool }); // POST: /Api/Notes awesome.api.Notes.Post({ form: formData }).done(function () { // .. do something cool });
This simple proxy will automatically distinguish query string parameters from request body parameters. 这个简单的代理将自动区分查询字符串参数和请求主体参数。 Missing parameters or multiple body-parameters will generate an error to prevent typo's or other common WebAPI development errors.
缺少参数或多个正文参数将生成错误以防止拼写错误或其他常见的WebAPI开发错误。
I'm working on the Swagger open-source toolchain NSwag for .NET: With this tool you can generate the TypeScript client for a single or multiple Web API controllers . 我正在使用Swagger开源工具链NSwag for .NET:使用此工具,您可以为单个或多个Web API控制器生成TypeScript客户端 。
In the UI just 在UI中
JQueryCallbacks
or JQueryPromises
template) JQueryCallbacks
或JQueryPromises
模板) Have a look at http://nswag.org 看看http://nswag.org
FYI: TypeScript is a language which gets transpiled to JavaScript 仅供参考: TypeScript是一种可以转换为JavaScript的语言
This excellent another project allows you to do what you asked for. 这个优秀的另一个项目可以让你做你想要的。 This poject auto-generates JavaScript proxies for MVC and WebApi controllers.
此项目自动生成MVC和WebApi控制器的JavaScript代理。 And, this project covers WebApi features such as custom ActionName attributes.
而且,该项目涵盖了WebApi功能,例如自定义ActionName属性。 With this project, you will have also the Intellisense.
通过这个项目,您还将拥有Intellisense。
http://jsnet.codeplex.com/ http://jsnet.codeplex.com/
Example of Intellisense 智能感知的例子
window.test = function test() {
/// <summary>
///This example works.
///You have the Intellisense. It's great!!!
///No hard coded url.
///</summary>
//-- settings of ajax request.
var a = $dpUrlSet.Customer.Create.$action0.$AjaxSettings();
//-- your parameters of action method
a.data.name = "Scott Gu";
a.data.address = "Somewhere in Redmond";
//-- stringify
a.data = JSON.stringify(a.data);
//-- send ajax request
var xhr = $.ajax(a);
xhr.success(function (id) {
/// <summary>Response of ajax request</summary>
//-- settings of ajax request.
var a = $dpUrlSet.Customer.Update.$action0.$AjaxSettings();
//-- your parameters of action method
a.data.id = id;
a.data.name = "Scott Gu";
a.data.address = "Somewhere in Seattle";
//-- stringify
a.data = JSON.stringify(a.data);
//-- send ajax request
var xhr = $.ajax(a);
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.