Line data Source code
1 : #region Copyright
2 : // // -----------------------------------------------------------------------
3 : // // <copyright company="Chinchilla Software Limited">
4 : // // Copyright Chinchilla Software Limited. All rights reserved.
5 : // // </copyright>
6 : // // -----------------------------------------------------------------------
7 : #endregion
8 :
9 : using System.Collections.Generic;
10 : using System.Linq;
11 : using System.Net;
12 : using System.Net.Http;
13 : using System.Text;
14 : using System.Web.Http;
15 : using System.Web.Http.Description;
16 : using Cqrs.Configuration;
17 :
18 : namespace Cqrs.WebApi.Controllers
19 : {
20 : /// <summary>
21 : /// A WebAPI RESTful service that provide a 'no configuration required' java-script client ready for developers to use.
22 : /// </summary>
23 : [RoutePrefix("Client")]
24 : public class ClientController : ApiController
25 1 : {
26 : /// <summary>
27 : /// A java-script file with a 'no configuration required' java-script client
28 : /// </summary>
29 : [Route("")]
30 : [HttpGet]
31 1 : public virtual HttpResponseMessage Index()
32 : {
33 : var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();
34 : var apiMethods = apiExplorer.ApiDescriptions.Select(ad => new ApiMethodModel(ad)).ToList();
35 :
36 : string host = Url.Content(Request.RequestUri.AbsoluteUri.Substring(0, Request.RequestUri.AbsoluteUri.Length - Request.RequestUri.AbsolutePath.Length));
37 : string path = Url.Content("~/");
38 : if (path.StartsWith(host))
39 : host = null;
40 :
41 : var responseBody = string.Format(@"window.api = window.api || {{
42 : metadata: {0},
43 : useJson: true,
44 : useXToken: true,
45 : cookieTokenName: '{3}',
46 : // This is because JQuery notes Global events are never fired for cross-domain script or JSONP requests, regardless of the value of global at https://api.jquery.com/category/ajax/global-ajax-event-handlers/
47 : globalHandlers: {{
48 : 'before' : function(jqXHR, settings) {{}},
49 : 'complete' : function(jqXHR, textStatus) {{}},
50 : 'error' : function(jqXHR, textStatus, errorThrown) {{}},
51 : 'success' : function(data, textStatus, jqXHR) {{}},
52 : 'setHeaders' : function()
53 : {{
54 : if (window.api.useXToken && typeof(Cookies) === 'function')
55 : {{
56 : var headers = {{}};
57 : headers[window.api.cookieTokenName] = Cookies.get(window.api.cookieTokenName);
58 : return headers;
59 : }}
60 : return {{}}
61 : }},
62 : '202' : function(data, textStatus, jqXHR) {{}},
63 : '300' : function(jqXHR, textStatus, errorThrown) {{}},
64 : '400' : function(jqXHR, textStatus, errorThrown) {{}},
65 : '401' : function(jqXHR, textStatus, errorThrown) {{}},
66 : '403' : function(jqXHR, textStatus, errorThrown) {{}},
67 : '404' : function(jqXHR, textStatus, errorThrown) {{}},
68 : '412' : function(jqXHR, textStatus, errorThrown) {{}},
69 : '500' : function(jqXHR, textStatus, errorThrown) {{}},
70 : }}
71 : }};
72 :
73 : $.each(window.api.metadata, function (i, action)
74 : {{
75 : if (!window.api[action.ControllerName])
76 : {{
77 : window.api[action.ControllerName] = {{}};
78 : }}
79 : window.api[action.ControllerName][action.ActionName] = function (parameters)
80 : {{
81 : var url = '{1}{2}' + action.Url;
82 : var data = {{}};
83 : var bodyParameters = 0;
84 : var complexParameters = 0;
85 :
86 : if (action.Parameters.length == 1 && action.Parameters[0].Name == 'parameters')
87 : {{
88 : bodyParameters = 1;
89 : data = parameters;
90 : }}
91 : else if (action.Parameters.length == 2 && action.Parameters[0].Name == 'entity' && action.Parameters[1].Name == 'rsn')
92 : {{
93 : bodyParameters = 1;
94 : url = url.substring(0, url.length - 5) + parameters['Rsn'];
95 : data = parameters;
96 : }}
97 : else
98 : {{
99 : var lastBodyParameter = null;
100 : $.each(action.Parameters, function (j, parameter)
101 : {{
102 : if (parameters[parameter.Name] === undefined)
103 : {{
104 : console.error('Missing parameter: ' + parameter.Name + ' for API: ' + action.ControllerName + '/' + action.ActionName);
105 : }}
106 : else if (parameter.IsUriParameter)
107 : {{
108 : url = url.replace('{{' + parameter.Name + '}}', parameters[parameter.Name]);
109 : }}
110 : else if (data[parameter.Name] === undefined)
111 : {{
112 : if (parameter.IsBodyParameter)
113 : {{
114 : bodyParameters++;
115 : lastBodyParameter = parameter.Name;
116 : }}
117 : else
118 : complexParameters++;
119 : data[parameter.Name] = parameters[parameter.Name];
120 : }}
121 : else
122 : {{
123 : console.error('Detected multiple body-parameters for API: ' + action.ControllerName + '/' + action.ActionName);
124 : }}
125 : }});
126 : }}
127 :
128 : if (bodyParameters == 1 && complexParameters == 0)
129 : data = data[lastBodyParameter];
130 :
131 : if (bodyParameters == 0 && complexParameters == 0)
132 : data = null;
133 :
134 : if (window.api.useJson)
135 : return $.ajax({{
136 : type: action.Method,
137 : url: url,
138 : data: data == null ? data : JSON.stringify(data),
139 : contentType: 'application/json',
140 : headers: window.api.globalHandlers['setHeaders'](),
141 : beforeSend: window.api.globalHandlers['before'],
142 : complete: window.api.globalHandlers['complete'],
143 : error: window.api.globalHandlers['error'],
144 : success: window.api.globalHandlers['success'],
145 : statusCode: {{
146 : 202: window.api.globalHandlers['202'],
147 : 300: window.api.globalHandlers['300'],
148 : 400: window.api.globalHandlers['400'],
149 : 401: window.api.globalHandlers['401'],
150 : 403: window.api.globalHandlers['403'],
151 : 404: window.api.globalHandlers['404'],
152 : 412: window.api.globalHandlers['412'],
153 : 500: window.api.globalHandlers['500']
154 : }}
155 : }});
156 : return $.ajax({{
157 : type: action.Method,
158 : url: url,
159 : data: data,
160 : headers: window.api.globalHandlers['setHeaders'](),
161 : beforeSend: window.api.globalHandlers['before'],
162 : complete: window.api.globalHandlers['complete'],
163 : error: window.api.globalHandlers['error'],
164 : success: window.api.globalHandlers['success'],
165 : statusCode: {{
166 : 202: window.api.globalHandlers['202'],
167 : 300: window.api.globalHandlers['300'],
168 : 400: window.api.globalHandlers['400'],
169 : 401: window.api.globalHandlers['401'],
170 : 403: window.api.globalHandlers['403'],
171 : 404: window.api.globalHandlers['404'],
172 : 412: window.api.globalHandlers['412'],
173 : 500: window.api.globalHandlers['500']
174 : }}
175 : }});
176 : }};
177 : }});",
178 : System.Web.Helpers.Json.Encode(apiMethods),
179 : host,
180 : path,
181 : DependencyResolver.Current.Resolve<IConfigurationManager>().GetSetting("Cqrs.Web.AuthenticationTokenName") ?? "X-Token");
182 :
183 : HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, responseBody);
184 : response.Content = new StringContent(responseBody, Encoding.UTF8, "application/javascript");
185 : return response;
186 : }
187 :
188 : /// <summary>
189 : /// A WebAPI action method.
190 : /// </summary>
191 : public class ApiMethodModel
192 1 : {
193 : /// <summary>
194 : /// The type of the <see cref="HttpMethod"/>.
195 : /// </summary>
196 : public string Method { get; set; }
197 :
198 : /// <summary>
199 : /// The URL of the action method.
200 : /// </summary>
201 : public string Url { get; set; }
202 :
203 : /// <summary>
204 : /// The name of the <see cref="ApiController"/> this action method is in.
205 : /// </summary>
206 : public string ControllerName { get; set; }
207 :
208 : /// <summary>
209 : /// The name of the action method.
210 : /// </summary>
211 : public string ActionName { get; set; }
212 :
213 : /// <summary>
214 : /// The <see cref="ApiParameterModel">parameters</see> of this action method.
215 : /// </summary>
216 : public IEnumerable<ApiParameterModel> Parameters { get; set; }
217 :
218 : /// <summary>
219 : /// Instantiates a new instance of <see cref="ApiMethodModel"/> with the provided <paramref name="apiDescription"/>.
220 : /// </summary>
221 1 : public ApiMethodModel(ApiDescription apiDescription)
222 : {
223 : Method = apiDescription.HttpMethod.Method;
224 : Url = apiDescription.RelativePath;
225 : ControllerName = apiDescription.ActionDescriptor.ControllerDescriptor.ControllerName;
226 : ActionName = apiDescription.ActionDescriptor.ActionName;
227 : Parameters = apiDescription.ParameterDescriptions.Select(pd => new ApiParameterModel(pd));
228 : }
229 : }
230 :
231 : /// <summary>
232 : /// A parameter for a WebAPI action method.
233 : /// </summary>
234 : public class ApiParameterModel
235 1 : {
236 : /// <summary>
237 : /// The name of the parameter.
238 : /// </summary>
239 : public string Name { get; set; }
240 :
241 : /// <summary>
242 : /// Indicates if the parameter is provided in the URL of the request or not.
243 : /// </summary>
244 : public bool IsUriParameter { get; set; }
245 :
246 : /// <summary>
247 : /// Indicates if the parameter is provided in the body of the request or not.
248 : /// </summary>
249 : public bool IsBodyParameter { get; set; }
250 :
251 : /// <summary>
252 : /// Instantiates a new instance of <see cref="ApiParameterModel"/> with the provided <paramref name="apiParameterDescription"/>.
253 : /// </summary>
254 1 : public ApiParameterModel(ApiParameterDescription apiParameterDescription)
255 : {
256 : Name = apiParameterDescription.Name;
257 : IsUriParameter = apiParameterDescription.Source == ApiParameterSource.FromUri;
258 : IsBodyParameter = apiParameterDescription.Source == ApiParameterSource.FromBody;
259 : }
260 : }
261 : }
262 : }
|