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.PathAndQuery.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)
55 : {{
56 : var headers = {{}};
57 : if (typeof(Cookies) === 'function')
58 : {{
59 : headers[window.api.cookieTokenName] = Cookies.get(window.api.cookieTokenName);
60 : }}
61 : else (typeof(Storage) !== ""undefined"")
62 : {{
63 : headers[window.api.cookieTokenName] = sessionStorage[window.api.cookieTokenName] || localStorage[window.api.cookieTokenName];
64 : }}
65 : return headers;
66 : }}
67 : return {{}}
68 : }},
69 : '202' : function(data, textStatus, jqXHR) {{}},
70 : '300' : function(jqXHR, textStatus, errorThrown) {{}},
71 : '400' : function(jqXHR, textStatus, errorThrown) {{}},
72 : '401' : function(jqXHR, textStatus, errorThrown) {{}},
73 : '403' : function(jqXHR, textStatus, errorThrown) {{}},
74 : '404' : function(jqXHR, textStatus, errorThrown) {{}},
75 : '412' : function(jqXHR, textStatus, errorThrown) {{}},
76 : '500' : function(jqXHR, textStatus, errorThrown) {{}},
77 : }}
78 : }};
79 :
80 : $.each(window.api.metadata, function (i, action)
81 : {{
82 : if (!window.api[action.ControllerName])
83 : {{
84 : window.api[action.ControllerName] = {{}};
85 : }}
86 : window.api[action.ControllerName][action.ActionName] = function (parameters, successFunction, errorFunction, statusCodeFunctions)
87 : {{
88 : var url = '{1}{2}' + action.Url;
89 : var data = {{}};
90 : var bodyParameters = 0;
91 : var complexParameters = 0;
92 :
93 : if (action.Parameters.length == 1 && action.Parameters[0].Name == 'parameters')
94 : {{
95 : bodyParameters = 1;
96 : data = parameters;
97 : }}
98 : else if (action.Parameters.length == 2 && ((action.Parameters[0].Name == 'entity' && action.Parameters[1].Name == 'rsn') || (action.Parameters[1].Name == 'parameters' && action.Parameters[0].Name == 'rsn')))
99 : {{
100 : bodyParameters = 1;
101 : url = url
102 : url = url.replace(/\/\{{rsn\}}/g, '\/' + parameters['Rsn']);
103 : data = (action.Parameters[1].Name == 'parameters' && Object.keys(parameters).length <= 1) ? null : parameters;
104 : }}
105 : else
106 : {{
107 : var lastBodyParameter = null;
108 : $.each(action.Parameters, function (j, parameter)
109 : {{
110 : if (parameters[parameter.Name] === undefined)
111 : {{
112 : console.error('Missing parameter: ' + parameter.Name + ' for API: ' + action.ControllerName + '/' + action.ActionName);
113 : }}
114 : else if (parameter.IsUriParameter)
115 : {{
116 : url = url.replace('{{' + parameter.Name + '}}', parameters[parameter.Name]);
117 : }}
118 : else if (data[parameter.Name] === undefined)
119 : {{
120 : if (parameter.IsBodyParameter)
121 : {{
122 : bodyParameters++;
123 : lastBodyParameter = parameter.Name;
124 : }}
125 : else
126 : complexParameters++;
127 : data[parameter.Name] = parameters[parameter.Name];
128 : }}
129 : else
130 : {{
131 : console.error('Detected multiple body-parameters for API: ' + action.ControllerName + '/' + action.ActionName);
132 : }}
133 : }});
134 : }}
135 :
136 : if (bodyParameters == 1 && complexParameters == 0 && lastBodyParameter != null && lastBodyParameter != '')
137 : data = data[lastBodyParameter];
138 :
139 : if (bodyParameters == 0 && complexParameters == 0)
140 : data = null;
141 :
142 : if (window.api.useJson)
143 : return $.ajax({{
144 : type: action.Method,
145 : url: url,
146 : data: data == null ? data : JSON.stringify(data),
147 : contentType: 'application/json',
148 : headers: window.api.globalHandlers['setHeaders'](),
149 : beforeSend: window.api.globalHandlers['before'],
150 : complete: window.api.globalHandlers['complete'],
151 : error: (errorFunction || window.api.globalHandlers['error']),
152 : success: (successFunction || window.api.globalHandlers['success']),
153 : statusCode: ( statusCodeFunctions || {{
154 : 202: window.api.globalHandlers['202'],
155 : 300: window.api.globalHandlers['300'],
156 : 400: window.api.globalHandlers['400'],
157 : 401: window.api.globalHandlers['401'],
158 : 403: window.api.globalHandlers['403'],
159 : 404: window.api.globalHandlers['404'],
160 : 412: window.api.globalHandlers['412'],
161 : 500: window.api.globalHandlers['500']
162 : }})
163 : }});
164 : return $.ajax({{
165 : type: action.Method,
166 : url: url,
167 : data: data,
168 : headers: window.api.globalHandlers['setHeaders'](),
169 : beforeSend: window.api.globalHandlers['before'],
170 : complete: window.api.globalHandlers['complete'],
171 : error: (errorFunction || window.api.globalHandlers['error']),
172 : success: (successFunction || window.api.globalHandlers['success']),
173 : statusCode: ( statusCodeFunctions || {{
174 : 202: window.api.globalHandlers['202'],
175 : 300: window.api.globalHandlers['300'],
176 : 400: window.api.globalHandlers['400'],
177 : 401: window.api.globalHandlers['401'],
178 : 403: window.api.globalHandlers['403'],
179 : 404: window.api.globalHandlers['404'],
180 : 412: window.api.globalHandlers['412'],
181 : 500: window.api.globalHandlers['500']
182 : }})
183 : }});
184 : }};
185 : }});",
186 : System.Web.Helpers.Json.Encode(apiMethods),
187 : host,
188 : path,
189 : DependencyResolver.Current.Resolve<IConfigurationManager>().GetSetting("Cqrs.Web.AuthenticationTokenName") ?? "X-Token");
190 :
191 : HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, responseBody);
192 : response.Content = new StringContent(responseBody, Encoding.UTF8, "application/javascript");
193 : return response;
194 : }
195 :
196 : /// <summary>
197 : /// A WebAPI action method.
198 : /// </summary>
199 : public class ApiMethodModel
200 1 : {
201 : /// <summary>
202 : /// The type of the <see cref="HttpMethod"/>.
203 : /// </summary>
204 : public string Method { get; set; }
205 :
206 : /// <summary>
207 : /// The URL of the action method.
208 : /// </summary>
209 : public string Url { get; set; }
210 :
211 : /// <summary>
212 : /// The name of the <see cref="ApiController"/> this action method is in.
213 : /// </summary>
214 : public string ControllerName { get; set; }
215 :
216 : /// <summary>
217 : /// The name of the action method.
218 : /// </summary>
219 : public string ActionName { get; set; }
220 :
221 : /// <summary>
222 : /// The <see cref="ApiParameterModel">parameters</see> of this action method.
223 : /// </summary>
224 : public IEnumerable<ApiParameterModel> Parameters { get; set; }
225 :
226 : /// <summary>
227 : /// Instantiates a new instance of <see cref="ApiMethodModel"/> with the provided <paramref name="apiDescription"/>.
228 : /// </summary>
229 1 : public ApiMethodModel(ApiDescription apiDescription)
230 : {
231 : Method = apiDescription.HttpMethod.Method;
232 : Url = apiDescription.RelativePath;
233 : ControllerName = apiDescription.ActionDescriptor.ControllerDescriptor.ControllerName;
234 : ActionName = apiDescription.ActionDescriptor.ActionName;
235 : Parameters = apiDescription.ParameterDescriptions.Select(pd => new ApiParameterModel(pd));
236 : }
237 : }
238 :
239 : /// <summary>
240 : /// A parameter for a WebAPI action method.
241 : /// </summary>
242 : public class ApiParameterModel
243 1 : {
244 : /// <summary>
245 : /// The name of the parameter.
246 : /// </summary>
247 : public string Name { get; set; }
248 :
249 : /// <summary>
250 : /// Indicates if the parameter is provided in the URL of the request or not.
251 : /// </summary>
252 : public bool IsUriParameter { get; set; }
253 :
254 : /// <summary>
255 : /// Indicates if the parameter is provided in the body of the request or not.
256 : /// </summary>
257 : public bool IsBodyParameter { get; set; }
258 :
259 : /// <summary>
260 : /// Instantiates a new instance of <see cref="ApiParameterModel"/> with the provided <paramref name="apiParameterDescription"/>.
261 : /// </summary>
262 1 : public ApiParameterModel(ApiParameterDescription apiParameterDescription)
263 : {
264 : Name = apiParameterDescription.Name;
265 : IsUriParameter = apiParameterDescription.Source == ApiParameterSource.FromUri;
266 : IsBodyParameter = apiParameterDescription.Source == ApiParameterSource.FromBody;
267 : }
268 : }
269 : }
270 : }
|