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.

811 lines
29 KiB

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