You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

873 lines
31 KiB

4 years ago
4 years ago
2 years ago
4 years ago
3 years ago
2 years ago
3 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
3 years ago
2 years ago
4 years ago
3 years ago
2 years ago
3 years ago
4 years ago
4 years ago
4 years ago
2 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
2 years ago
3 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
4 years ago
2 years ago
4 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
2 years ago
4 years ago
4 years ago
2 years ago
2 years ago
4 years ago
2 years ago
2 years ago
4 years ago
4 years ago
4 years ago
4 years ago
2 years ago
4 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
3 years ago
4 years ago
2 years ago
3 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
4 years ago
3 years ago
4 years ago
2 years ago
4 years ago
3 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
2 years ago
4 years ago
2 years ago
2 years ago
4 years ago
2 years ago
2 years ago
4 years ago
3 years ago
4 years ago
4 years ago
  1. using Apewer.Internals;
  2. using Apewer.Network;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Net;
  6. using System.Reflection;
  7. using static Apewer.Web.ApiUtility;
  8. namespace Apewer.Web
  9. {
  10. internal class ApiProcessor
  11. {
  12. private ApiContext _context = null;
  13. internal ApiProcessor(ApiContext context) => _context = context ?? throw new ArgumentNullException(nameof(context));
  14. #region prepare
  15. /// <summary>执行处理程序,返回错误信息。</summary>
  16. public void Run()
  17. {
  18. var url = null as Uri;
  19. var method = HttpMethod.NULL;
  20. var response = null as ApiResponse;
  21. try
  22. {
  23. // 检查执行的前提条件,获取 Method 和 URL。
  24. var check = Check(ref method, ref url);
  25. if (!string.IsNullOrEmpty(check))
  26. {
  27. Logger.Internals.Error(typeof(ApiInvoker), check);
  28. return;
  29. }
  30. // 准备请求模型。
  31. var request = GetRequest(_context.Provider, _context.Options, method, url);
  32. _context.Request = request;
  33. // 准备响应模型。
  34. response = new ApiResponse();
  35. response.Random = request.Random;
  36. response.Application = request.Application;
  37. response.Function = request.Function;
  38. _context.Response = response;
  39. // OPTIONS
  40. if (_context.Request.Method == HttpMethod.OPTIONS)
  41. {
  42. if (!_context.Options.AllowOptions)
  43. {
  44. _context.Response.Model = new ApiTextModel("");
  45. return;
  46. }
  47. }
  48. // 中间件
  49. var middlewares = _context.Invoker.Middlewares;
  50. if (middlewares.Length > 0)
  51. {
  52. // 设置队列和回调。
  53. _mw_queue = new Queue<ApiMiddleware>(middlewares);
  54. _context.SetMiddlewareCallback(MiddlewareNext);
  55. // 执行。
  56. MiddlewareNext(_context);
  57. }
  58. else
  59. {
  60. // 无中间件。
  61. Route();
  62. }
  63. }
  64. catch (Exception ex)
  65. {
  66. ApiUtility.Exception(_context.Response, ex, _context.Options.WithException);
  67. var message = ex.Message();
  68. Logger.Internals.Error(typeof(ApiInvoker), message);
  69. }
  70. finally
  71. {
  72. // 输出。
  73. if (response != null)
  74. {
  75. try
  76. {
  77. response.Duration = Duration(_context.Beginning);
  78. Output(_context.Provider, _context.Options, response, null, method);
  79. }
  80. catch { }
  81. finally
  82. {
  83. RuntimeUtility.Dispose(response.Model);
  84. }
  85. }
  86. }
  87. }
  88. static string Duration(DateTime beginning)
  89. {
  90. var span = DateTime.Now - beginning;
  91. var ms = span.TotalMilliseconds;
  92. if (ms < 1000) return Math.Round(ms, 0).ToString() + "ms";
  93. if (ms < 10000) return Math.Round(ms / 1000, 2).ToString() + "s";
  94. if (ms < 60000) return Math.Round(ms / 1000, 1).ToString() + "s";
  95. return Math.Round(ms / 1000, 0).ToString() + "s";
  96. }
  97. string Check(ref HttpMethod method, ref Uri url)
  98. {
  99. // 服务程序检查。
  100. var check = _context.Provider.PreInvoke();
  101. if (!string.IsNullOrEmpty(check)) return check;
  102. // URL
  103. url = _context.Provider.GetUrl();
  104. if (url == null) return "URL 无效。";
  105. // Method
  106. method = _context.Provider.GetMethod();
  107. switch (method)
  108. {
  109. case HttpMethod.NULL:
  110. return "HTTP 方法无效。";
  111. case HttpMethod.OPTIONS:
  112. if (!_context.Options.AllowOptions) return null;
  113. break;
  114. }
  115. // favicon.ico
  116. var lowerPath = TextUtility.AssureStarts(TextUtility.Lower(url.AbsolutePath), "/");
  117. if (!_context.Options.AllowFavIcon)
  118. {
  119. if (lowerPath.StartsWith("/favicon.ico"))
  120. {
  121. Output(_context.Provider, _context.Options, null, null, null);
  122. return "已取消对 favicon.ico 的请求。";
  123. }
  124. }
  125. // robots.txt
  126. if (!_context.Options.AllowRobots)
  127. {
  128. if (lowerPath.StartsWith("/robots.txt"))
  129. {
  130. const string text = "User-agent: *\nDisallow: / \n";
  131. Output(_context.Provider, _context.Options, null, "text/plain", TextUtility.Bytes(text));
  132. return "已取消对 robots.txt 的请求。";
  133. }
  134. }
  135. return null;
  136. }
  137. #endregion
  138. #region common
  139. static Type Void = typeof(void);
  140. // 创建控制器实例
  141. static ApiController CreateController(Type type, ApiContext context)
  142. {
  143. var controller = (ApiController)Activator.CreateInstance(type);
  144. ApiUtility.SetContext(controller, context);
  145. return controller;
  146. }
  147. static void Invoke(ApiContext context, MethodInfo method, ApiParameter[] parameters)
  148. {
  149. context.MethodInfo = method;
  150. // 调用。
  151. var parametersValue = ReadParameters(context.Request, parameters);
  152. var controller = context.Controller;
  153. var returnValue = method.Invoke(controller, parametersValue);
  154. // 程序要求停止输出。
  155. var response = context.Response;
  156. if (response.StopReturn) return;
  157. // 已经有了返回模型。
  158. if (response.Model != null) return;
  159. // 没有返回类型。
  160. var returnType = method.ReturnType;
  161. if (returnType == null || returnType.Equals(Void)) return;
  162. // 已明确字符串类型。
  163. if (returnType.Equals(typeof(string)))
  164. {
  165. var textValue = returnValue as string;
  166. var textRenderer = context.Options.TextRenderer;
  167. if (textRenderer != null)
  168. {
  169. textRenderer.Invoke(context, textValue);
  170. return;
  171. }
  172. // 默认视为提示错误
  173. if (!string.IsNullOrEmpty(textValue)) response.Error(textValue);
  174. return;
  175. }
  176. // 已明确 Exception 类型,视为提示错误。
  177. if (returnValue is Exception)
  178. {
  179. ApiUtility.Exception(response, returnValue as Exception);
  180. return;
  181. }
  182. // 已明确 Json 类型。
  183. if (returnValue is Json json)
  184. {
  185. var renderer = context.Options.JsonRenderer;
  186. if (renderer != null)
  187. {
  188. renderer.Invoke(context, json);
  189. return;
  190. }
  191. // 默认设置到 data 属性。
  192. response.Data = json;
  193. return;
  194. }
  195. // 已明确 Model 类型。
  196. if (returnValue is IApiModel model)
  197. {
  198. response.Model = model;
  199. return;
  200. }
  201. // 已明确 Result 类型。
  202. if (returnValue is IActionResult result)
  203. {
  204. response.Model = result;
  205. return;
  206. }
  207. // 类型未知,尝试 ToJson 方法。
  208. if (returnValue is IToJson toJson)
  209. {
  210. var tojson = toJson.ToJson();
  211. var renderer = context.Options.JsonRenderer;
  212. if (renderer != null)
  213. {
  214. renderer.Invoke(context, tojson);
  215. return;
  216. }
  217. response.Data = tojson;
  218. return;
  219. }
  220. // 未知返回类型,尝试使用默认渲染器。
  221. var defaultRenderer = context.Options.DefaultRenderer;
  222. if (defaultRenderer != null) defaultRenderer.Invoke(context, returnValue);
  223. }
  224. #endregion
  225. #region middleware
  226. Queue<ApiMiddleware> _mw_queue = null;
  227. void MiddlewareNext(ApiContext context)
  228. {
  229. if (_mw_queue.Count < 1)
  230. {
  231. Route();
  232. return;
  233. }
  234. // 创建下一个中间件的实例
  235. var middleware = _mw_queue.Dequeue();
  236. if (middleware.Type != null)
  237. {
  238. var instance = Activator.CreateInstance(middleware.Type) as IApiMiddleware;
  239. if (instance == null) throw new Exception($"类型【{middleware.Type.FullName}】不是有效的中间件。");
  240. // 调用
  241. instance.Invoke(context);
  242. }
  243. else if (middleware.Callback != null)
  244. {
  245. middleware.Callback.Invoke(context, () => MiddlewareNext(context));
  246. }
  247. else
  248. {
  249. MiddlewareNext(context);
  250. }
  251. }
  252. // 执行路由。
  253. void Route()
  254. {
  255. // 路由
  256. if (_context.Options.UseRoute)
  257. {
  258. var path = _context?.Request?.Url?.AbsolutePath;
  259. path = path.TrimEnd('/');
  260. var action = _context.Entries.GetAction(path);
  261. if (action != null)
  262. {
  263. _context.ApiAction = action;
  264. if (action.Unparallel)
  265. {
  266. UnparallelLocker.InLock(GetUnparallelKey(action.MethodInfo), () =>
  267. {
  268. InvokeAction(action);
  269. });
  270. }
  271. else
  272. {
  273. InvokeAction(action);
  274. }
  275. return;
  276. }
  277. }
  278. // 反射
  279. if (_context.Options.UseReflection)
  280. {
  281. var appName = _context.Request.Application;
  282. var application = _context.Entries.GetApplication(appName);
  283. InvokeApplication(application);
  284. return;
  285. }
  286. // 未匹配到
  287. _context.Response.Duration = Duration(_context.Beginning);
  288. _context.Response.Model = new ApiStatusModel(404);
  289. }
  290. #endregion
  291. #region route
  292. // 执行 Action。
  293. void InvokeAction(ApiAction action)
  294. {
  295. var controller = null as ApiController;
  296. try
  297. {
  298. // 准备控制器。
  299. controller = CreateController(action.Type, _context);
  300. // 准备参数。
  301. var parameters = action.Parameters;
  302. var values = ReadParameters(_context.Request, parameters);
  303. // 调用。
  304. _context.Controller = controller;
  305. Invoke(_context, action.MethodInfo, action.Parameters);
  306. }
  307. catch (Exception ex)
  308. {
  309. if (ex.InnerException != null) ex = ex.InnerException;
  310. ApiUtility.Exception(_context.Response, ex, _context.Options.WithException);
  311. var catcher = _context.Invoker.Catcher;
  312. if (catcher != null)
  313. {
  314. try
  315. {
  316. var apiCatch = new ApiCatch(_context, ex);
  317. catcher.Invoke(apiCatch);
  318. }
  319. catch { }
  320. }
  321. }
  322. finally
  323. {
  324. RuntimeUtility.Dispose(controller);
  325. }
  326. }
  327. #endregion
  328. #region reflection
  329. // 创建控制器。
  330. void InvokeApplication(ApiApplication application)
  331. {
  332. var options = _context.Options;
  333. var entries = _context.Entries;
  334. var request = _context.Request;
  335. var response = _context.Response;
  336. // Application 无效,尝试默认控制器和枚举。
  337. if (application == null)
  338. {
  339. var @default = options.Default;
  340. if (@default == null)
  341. {
  342. // 没有指定默认控制器,尝试枚举。
  343. response.Status = "notfound";
  344. response.Message = "Not Found";
  345. if (options.AllowEnumerate) response.Data = Enumerate(entries.Applications, options);
  346. return;
  347. }
  348. else
  349. {
  350. // 创建默认控制器。
  351. var controller = null as ApiController;
  352. try
  353. {
  354. var unparallel = @default.Contains<UnparallelAttribute>(false);
  355. if (unparallel)
  356. {
  357. UnparallelLocker.InLock(GetUnparallelKey(@default), () =>
  358. {
  359. controller = CreateController(@default, _context);
  360. InvokeFunction(controller, application, null, options, request, response);
  361. });
  362. }
  363. else
  364. {
  365. controller = CreateController(@default, _context);
  366. InvokeFunction(controller, application, null, options, request, response);
  367. }
  368. }
  369. catch (Exception ex)
  370. {
  371. ApiUtility.Exception(response, ex.InnerException ?? ex);
  372. }
  373. finally
  374. {
  375. RuntimeUtility.Dispose(controller);
  376. }
  377. }
  378. }
  379. else
  380. {
  381. // 创建控制器时候会填充 Controller.Request 属性,可能导致 Request.Function 被篡改,所以在创建之前获取 Function。
  382. var function = application.GetFunction(request.Function);
  383. var controller = null as ApiController;
  384. try
  385. {
  386. if (application.Unparallel)
  387. {
  388. UnparallelLocker.InLock(GetUnparallelKey(application.Type), () =>
  389. {
  390. controller = CreateController(application.Type, _context);
  391. InvokeFunction(controller, application, function, options, request, response);
  392. });
  393. }
  394. else if (function != null && function.Unparallel)
  395. {
  396. UnparallelLocker.InLock(GetUnparallelKey(function.Method), () =>
  397. {
  398. controller = CreateController(application.Type, _context);
  399. InvokeFunction(controller, application, function, options, request, response);
  400. });
  401. }
  402. else
  403. {
  404. controller = CreateController(application.Type, _context);
  405. InvokeFunction(controller, application, function, options, request, response);
  406. }
  407. }
  408. catch (Exception ex)
  409. {
  410. ApiUtility.Exception(response, ex.InnerException ?? ex);
  411. }
  412. finally
  413. {
  414. RuntimeUtility.Dispose(controller);
  415. }
  416. }
  417. }
  418. // 调用 Function。
  419. void InvokeFunction(ApiController controller, ApiApplication application, ApiFunction function, ApiOptions options, ApiRequest request, ApiResponse response)
  420. {
  421. try
  422. {
  423. // 控制器初始化。
  424. var initializer = ApiUtility.GetInitialier(controller);
  425. if (initializer != null)
  426. {
  427. var @continue = true;
  428. @continue = initializer.Invoke(controller);
  429. if (!@continue) return;
  430. }
  431. // 此应用独立处理,不受反射控制。
  432. if (application.Independent) return;
  433. if (function != null)
  434. {
  435. // 调用 API,获取返回值。
  436. _context.Controller = controller;
  437. Invoke(_context, function.Method, function.Parameters);
  438. }
  439. else
  440. {
  441. // 未匹配到 Function,尝试 Default。
  442. var @default = ApiUtility.GetDefault(controller);
  443. if (@default != null)
  444. {
  445. @default.Invoke(controller);
  446. return;
  447. }
  448. // 没有执行任何 Function,尝试枚举。
  449. response.Status = "notfound";
  450. if (application.Hidden)
  451. {
  452. response.Message = "Not Found";
  453. }
  454. else
  455. {
  456. response.Message = "Not Found";
  457. if (options.AllowEnumerate) response.Data = Enumerate(application.Functions, options);
  458. }
  459. }
  460. }
  461. catch (Exception ex)
  462. {
  463. if (ex.InnerException != null) ex = ex.InnerException;
  464. ApiUtility.Exception(_context.Response, ex, _context.Options.WithException);
  465. var catcher = _context.Invoker.Catcher;
  466. if (catcher != null)
  467. {
  468. try
  469. {
  470. var apiCatch = new ApiCatch(_context, ex);
  471. catcher.Invoke(apiCatch);
  472. }
  473. catch { }
  474. }
  475. }
  476. }
  477. #endregion
  478. #region static
  479. internal static ApiRequest GetRequest(ApiProvider provider, ApiOptions options, HttpMethod method, Uri url)
  480. {
  481. // 创建数据对象。
  482. var request = new ApiRequest();
  483. // Http Method。
  484. request.Method = method;
  485. // 基本信息。
  486. var ip = provider.GetClientIP();
  487. var headers = provider.GetHeaders() ?? new HttpHeaders();
  488. request.Headers = headers;
  489. request.IP = ip;
  490. request.Url = url;
  491. request.Referrer = provider.GetReferrer();
  492. request.Parameters = ApiUtility.Parameters(url.Query);
  493. // Headers。
  494. request.UserAgent = ApiUtility.UserAgent(headers);
  495. request.Cookies = ParseCookies(headers) ?? new CookieCollection();
  496. // 匹配 API。
  497. var application = null as string;
  498. var function = null as string;
  499. var random = null as string;
  500. var ticket = null as string;
  501. var session = null as string;
  502. var page = null as string;
  503. // 解析 POST 请求。
  504. switch (request.Method)
  505. {
  506. case HttpMethod.PATCH:
  507. case HttpMethod.POST:
  508. case HttpMethod.PUT:
  509. var preRead = provider.PreRead();
  510. if (string.IsNullOrEmpty(preRead))
  511. {
  512. var post = null as byte[];
  513. var length = 0L;
  514. var max = options.MaxRequestBody;
  515. if (max == 0) post = new byte[0];
  516. else if (max < 0) post = provider.RequestBody().Read();
  517. else
  518. {
  519. length = provider.GetContentLength();
  520. if (length <= max) post = provider.RequestBody().Read();
  521. }
  522. length = post == null ? 0 : post.Length;
  523. if (length > 1)
  524. {
  525. request.PostData = post;
  526. if (length < 104857600)
  527. {
  528. var text = TextUtility.FromBytes(post);
  529. request.PostText = text;
  530. // 尝试解析 Json,首尾必须是“{}”或“[]”。
  531. var first = post[0];
  532. var last = post[length - 1];
  533. if ((first == 123 && last == 125) || (first == 91 && last == 93))
  534. {
  535. var json = Json.From(text);
  536. if (json != null && json.IsObject)
  537. {
  538. application = json["application"];
  539. function = json["function"];
  540. random = json["random"];
  541. ticket = json["ticket"];
  542. session = json["session"];
  543. page = json["page"];
  544. var data = json.GetProperty("data");
  545. request.PostJson = json;
  546. request.Data = data ?? Json.NewObject();
  547. }
  548. }
  549. // 尝试解析 Form,需要 application/x-www-form-urlencoded
  550. var contentType = headers.GetValue("Content-Type") ?? "";
  551. if (contentType.Contains("urlencoded")) request.Form = ApiUtility.Parameters(text);
  552. }
  553. }
  554. }
  555. break;
  556. }
  557. // 解析 URL 参数。
  558. // URL 参数的优先级应高于 URL 路径,以避免反向代理产生的路径问题。
  559. var urlParameters = ApiUtility.Parameters(request.Url.Query);
  560. if (string.IsNullOrEmpty(application)) application = urlParameters.GetValue("application");
  561. if (string.IsNullOrEmpty(function)) function = urlParameters.GetValue("function");
  562. if (string.IsNullOrEmpty(random)) random = urlParameters.GetValue("random");
  563. if (string.IsNullOrEmpty(ticket)) ticket = urlParameters.GetValue("ticket");
  564. if (string.IsNullOrEmpty(session)) session = urlParameters.GetValue("session");
  565. if (string.IsNullOrEmpty(page)) page = urlParameters.GetValue("page");
  566. // 从 Cookie 中获取 Ticket。
  567. var cookies = request.Cookies;
  568. if (string.IsNullOrEmpty(ticket)) ticket = cookies.GetValue("ticket");
  569. // 最后检查 URL 路径。
  570. var paths = (request.Url.AbsolutePath ?? "").Split('/');
  571. if (string.IsNullOrEmpty(application) && paths.Length >= 2) application = TextUtility.DecodeUrl(paths[1]);
  572. if (string.IsNullOrEmpty(function) && paths.Length >= 3) function = TextUtility.DecodeUrl(paths[2]);
  573. // 修正内容。
  574. application = TextUtility.Trim(application);
  575. function = TextUtility.Trim(function);
  576. random = TextUtility.Trim(random);
  577. ticket = TextUtility.Trim(ticket);
  578. session = TextUtility.Trim(session);
  579. page = TextUtility.Trim(page);
  580. // 设置请求:回传。
  581. request.Application = application;
  582. request.Function = function;
  583. request.Random = random;
  584. // 设置请求:不回传。
  585. request.Ticket = ticket;
  586. request.Session = session;
  587. request.Page = page;
  588. return request;
  589. }
  590. static StringPairs PrepareHeaders(ApiOptions options, ApiResponse response, ApiRequest request = null)
  591. {
  592. var merged = new StringPairs();
  593. if (options != null)
  594. {
  595. // 跨域访问。
  596. if (options.WithAccessControl)
  597. {
  598. merged.Add("Access-Control-Allow-Headers", "Content-Type");
  599. merged.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
  600. merged.Add("Access-Control-Allow-Origin", "*");
  601. var maxage = options.AccessControlMaxAge;
  602. if (maxage > 0) merged.Add("Access-Control-Max-Age", maxage.ToString());
  603. if (request != null && request.Headers != null)
  604. {
  605. var @private = request.Headers.GetValue("Access-Control-Request-Private-Network");
  606. if (NumberUtility.Boolean(@private)) merged.Add("Access-Control-Allow-Private-Network", "true");
  607. }
  608. }
  609. // Content-Type 检查。
  610. if (options.WithContentTypeOptions)
  611. {
  612. merged.Add("X-Content-Type-Options", "nosniff");
  613. }
  614. // 用于客户端,当前页面使用 HTTPS 时,将资源升级为 HTTPS。
  615. if (options.UpgradeHttps)
  616. {
  617. merged.Add("Content-Security-Policy", "upgrade-insecure-requests");
  618. }
  619. // 包含 API 的处理时间。
  620. if (options.WithDuration && response != null)
  621. {
  622. if (response.Duration.NotEmpty()) merged.Add("Duration", response.Duration);
  623. }
  624. }
  625. if (response != null)
  626. {
  627. // Cookies。
  628. var setCookies = SetCookie(response.Cookies);
  629. if (setCookies != null)
  630. {
  631. foreach (var value in setCookies) merged.Add("Set-Cookie", value);
  632. }
  633. // 自定义头。
  634. var headers = response.Headers;
  635. if (headers != null)
  636. {
  637. foreach (var header in headers)
  638. {
  639. var key = TextUtility.Trim(header.Name);
  640. if (string.IsNullOrEmpty(key)) continue;
  641. var value = header.Value;
  642. if (string.IsNullOrEmpty(value)) continue;
  643. merged.Add(key, value);
  644. }
  645. }
  646. }
  647. return merged;
  648. }
  649. internal void Output(ApiProvider provider, ApiOptions options, ApiResponse response, string type, byte[] bytes)
  650. {
  651. var preWrite = provider.PreWrite();
  652. if (!string.IsNullOrEmpty(preWrite)) return;
  653. if (response != null)
  654. {
  655. var responsePreOutput = response.PreOutput;
  656. if (responsePreOutput != null)
  657. {
  658. var @continue = responsePreOutput.Invoke(_context);
  659. if (!@continue) return;
  660. }
  661. }
  662. var invokerPreOutput = _context.Invoker.PreOutput;
  663. if (invokerPreOutput != null)
  664. {
  665. var @continue = invokerPreOutput.Invoke(_context);
  666. if (!@continue) return;
  667. }
  668. var optionsPreOutput = _context.Options.PreOutput;
  669. if (optionsPreOutput != null)
  670. {
  671. var @continue = optionsPreOutput.Invoke(_context);
  672. if (!@continue) return;
  673. }
  674. var headers = PrepareHeaders(options, response);
  675. foreach (var header in headers) provider.SetHeader(header.Key, header.Value);
  676. provider.SetCache(0);
  677. provider.SetContentType(string.IsNullOrEmpty(type) ? "application/octet-stream" : type);
  678. var length = bytes == null ? 0 : bytes.Length;
  679. provider.SetContentLength(length);
  680. if (length > 0) provider.ResponseBody().Write(bytes, 0, bytes.Length);
  681. provider.Sent();
  682. }
  683. internal void Output(ApiProvider provider, ApiOptions options, ApiResponse response, ApiRequest request, HttpMethod method)
  684. {
  685. var preWrite = provider.PreWrite();
  686. if (!string.IsNullOrEmpty(preWrite)) return;
  687. if (response != null)
  688. {
  689. var responsePreOutput = response.PreOutput;
  690. if (responsePreOutput != null)
  691. {
  692. var @continue = responsePreOutput.Invoke(_context);
  693. if (!@continue) return;
  694. }
  695. }
  696. var invokerPreOutput = _context.Invoker.PreOutput;
  697. if (invokerPreOutput != null)
  698. {
  699. var @continue = invokerPreOutput.Invoke(_context);
  700. if (!@continue) return;
  701. }
  702. var optionsPreOutput = _context.Options.PreOutput;
  703. if (optionsPreOutput != null)
  704. {
  705. var @continue = optionsPreOutput.Invoke(_context);
  706. if (!@continue) return;
  707. }
  708. // 设置头。
  709. var headers = PrepareHeaders(options, response, request);
  710. foreach (var header in headers) provider.SetHeader(header.Key, header.Value);
  711. // 自定义模型
  712. var model = response.Model as IApiModel;
  713. var result = response.Model as IActionResult;
  714. if (model != null)
  715. {
  716. try
  717. {
  718. model.Output(_context);
  719. }
  720. catch (Exception ex)
  721. {
  722. Logger.Internals.Exception(ex, model);
  723. }
  724. RuntimeUtility.Dispose(model);
  725. return;
  726. }
  727. else if (result != null)
  728. {
  729. try
  730. {
  731. result.ExecuteResult(_context);
  732. }
  733. catch (Exception ex)
  734. {
  735. Logger.Internals.Exception(ex, result);
  736. }
  737. RuntimeUtility.Dispose(result);
  738. return;
  739. }
  740. var text = ApiUtility.ToJson(response, options);
  741. var bytes = TextUtility.Bytes(text);
  742. provider.SetCache(0);
  743. provider.SetContentType("text/json; charset=utf-8");
  744. provider.SetContentLength(bytes.Length);
  745. var stream = provider.ResponseBody();
  746. if (stream != null && stream.CanWrite) stream.Write(bytes, 0, bytes.Length);
  747. provider.Sent();
  748. }
  749. #endregion
  750. #region 不可并行
  751. static TextLocker UnparallelLocker = new TextLocker();
  752. static string GetUnparallelKey(MethodInfo method)
  753. {
  754. return $"{method.DeclaringType.Assembly.ToString()} | {method.DeclaringType.FullName} | {method.ToString()}";
  755. }
  756. static string GetUnparallelKey(Type type)
  757. {
  758. return $"{type.Assembly.ToString()} | {type.FullName}";
  759. }
  760. #endregion
  761. }
  762. }