简体   繁体   English

基于ASP.NET WebAPI控件生成JS客户端

[英]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生成客户端。

  1. Has this been done before? 以前做过吗?
  2. Are there other ways to tie ASP.NET WebAPI and JavaScript together without writing a bunch of AJAX boilerplate code? 有没有其他方法可以将ASP.NET WebAPI和JavaScript结合在一起,而无需编写大量的AJAX样板代码?
  3. In other words, are there frameworks for creating JS-interfaces based on server-side interfaces like ASP.NET WebAPI? 换句话说,是否存在基于ASP.NET WebAPI等服务器端接口创建JS接口的框架?

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中

  1. Select the Web API DLL 选择Web API DLL
  2. Select the controller classes 选择控制器类
  3. Generate TypeScript client code (in your case, select the JQueryCallbacks or JQueryPromises template) 生成TypeScript客户端代码(在您的情况下,选择JQueryCallbacksJQueryPromises模板)

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM