PageRenderTime 58ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/wojilu/Web/Mvc/ControllerBase.cs

https://bitbucket.org/kingshine/wojilu
C# | 1147 lines | 524 code | 209 blank | 414 comment | 76 complexity | 7296cc7499de371a2df320bc0e3d64e8 MD5 | raw file
Possible License(s): MIT
  1. /*
  2. * Copyright 2010 www.wojilu.com
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. using System;
  17. using System.Collections;
  18. using System.Collections.Generic;
  19. using System.Reflection;
  20. using System.Text;
  21. using wojilu.Reflection;
  22. using wojilu.Web.Mvc.Attr;
  23. using wojilu.Web.Mvc.Interface;
  24. using wojilu.Web.Mvc.Utils;
  25. using wojilu.Web.Context;
  26. using wojilu.DI;
  27. namespace wojilu.Web.Mvc {
  28. /// <summary>
  29. /// 控制器基类,wojilu mvc 中最常使用的对象
  30. /// </summary>
  31. public abstract class ControllerBase {
  32. /// <summary>
  33. /// 链接控件
  34. /// </summary>
  35. public Link Link;
  36. /// <summary>
  37. /// 当前 controller 中发生的错误信息
  38. /// </summary>
  39. protected Result errors;
  40. /// <summary>
  41. /// 当前mvc的上下文(context),包括一些通用的数据和方法
  42. /// </summary>
  43. public MvcContext ctx;
  44. /// <summary>
  45. /// 设置或获取布局控制器
  46. /// </summary>
  47. public Type LayoutControllerType;
  48. private ControllerCore _utils;
  49. /// <summary>
  50. /// 页面元信息(包括Title/Keywords/Description/RssLink)
  51. /// </summary>
  52. public PageMeta Page {
  53. get { return this.ctx.GetPageMeta(); }
  54. }
  55. internal void setContext( MvcContext wctx ) {
  56. ctx = wctx;
  57. Link = new Link( wctx );
  58. errors = wctx.errors;
  59. _utils = new ControllerCore( this );
  60. }
  61. /// <summary>
  62. /// 一些帮助方法,主要是框架调用
  63. /// </summary>
  64. public ControllerCore utils {
  65. get { return _utils; }
  66. }
  67. /// <summary>
  68. /// 检查权限
  69. /// </summary>
  70. public virtual void CheckPermission() { }
  71. /// <summary>
  72. /// 布局方法
  73. /// </summary>
  74. public virtual void Layout() { }
  75. internal readonly List<Type> hidedLayouts = new List<Type>();
  76. internal readonly List<Type> hidedPermission = new List<Type>();
  77. /// <summary>
  78. /// 隐藏某个布局
  79. /// </summary>
  80. /// <param name="layoutType">需要被隐藏的 LayoutController 类型</param>
  81. public void HideLayout( Type layoutType ) {
  82. hidedLayouts.Add( layoutType );
  83. }
  84. /// <summary>
  85. /// 隐藏某个权限检查步骤
  86. /// </summary>
  87. /// <param name="layoutType">需要被隐藏的权限检查 controller 类型</param>
  88. protected void HidePermission( Type layoutType ) {
  89. hidedPermission.Add( layoutType );
  90. }
  91. //-------------------------------------- 绑定 ----------------------------------------------
  92. /// <summary>
  93. /// 绑定链接
  94. /// </summary>
  95. /// <param name="tpl"></param>
  96. /// <param name="lbl"></param>
  97. /// <param name="obj"></param>
  98. protected virtual void bindOtherLink( IBlock tpl, String lbl, Object obj ) {
  99. }
  100. /// <summary>
  101. /// 根据名称获取模板中某个block
  102. /// </summary>
  103. /// <param name="blockName">block名称</param>
  104. /// <returns></returns>
  105. protected IBlock getBlock( String blockName ) {
  106. return utils.getCurrentView().GetBlock( blockName );
  107. }
  108. /// <summary>
  109. /// 手动指定当前 action 的视图文件(指定视图文件之后,默认的模板将被忽略)
  110. /// </summary>
  111. /// <param name="actionViewName">视图文件的名称</param>
  112. public void view( String actionViewName ) {
  113. utils.setCurrentView( utils.getTemplateByAction( actionViewName ) );
  114. }
  115. /// <summary>
  116. /// 自定义当前视图模的内容(自定义内容之后,默认的模板将被忽略)
  117. /// </summary>
  118. /// <param name="templateContent">模板的内容</param>
  119. public void viewContent( String templateContent ) {
  120. Template t = new Template();
  121. t.InitContent( templateContent );
  122. utils.setCurrentView( t );
  123. }
  124. /// <summary>
  125. /// 给模板中的变量赋值
  126. /// </summary>
  127. /// <param name="lbl">变量名称</param>
  128. /// <param name="val"></param>
  129. public void set( String lbl, Object val ) {
  130. utils.getCurrentView().Set( lbl, val );
  131. }
  132. /// <summary>
  133. /// 给模板中的变量赋值
  134. /// </summary>
  135. /// <param name="lbl">变量名称</param>
  136. /// <param name="val"></param>
  137. public void set( String lbl, String val ) {
  138. utils.getCurrentView().Set( lbl, val );
  139. }
  140. /// <summary>
  141. /// 将对象绑定到模板
  142. /// </summary>
  143. /// <param name="val"></param>
  144. protected void bind( Object val ) {
  145. utils.getCurrentView().Bind( val );
  146. }
  147. /// <summary>
  148. /// 将对象绑定到模板,并指定对象在模板中的变量名
  149. /// </summary>
  150. /// <param name="lbl">对象在模板中的变量名</param>
  151. /// <param name="val"></param>
  152. protected void bind( String lbl, Object val ) {
  153. utils.getCurrentView().Bind( lbl, val );
  154. }
  155. /// <summary>
  156. /// 将对象列表绑定到模板
  157. /// </summary>
  158. /// <param name="listName">需要被绑定的列表名</param>
  159. /// <param name="lbl">对象在模板中的变量名</param>
  160. /// <param name="objList">对象的列表</param>
  161. protected void bindList( String listName, String lbl, IList objList ) {
  162. bindList( listName, lbl, objList, bindOtherLink );
  163. }
  164. /// <summary>
  165. /// 将对象列表绑定到模板
  166. /// </summary>
  167. /// <param name="listName">需要被绑定的列表名</param>
  168. /// <param name="lbl">对象在模板中的变量名</param>
  169. /// <param name="objList">对象的列表</param>
  170. /// <param name="otherBinder">附加的绑定器otherBindFunction( IBlock tpl, String lbl, Object obj )</param>
  171. protected void bindList( String listName, String lbl, IList objList, otherBindFunction otherBinder ) {
  172. utils.getCurrentView().bindOtherFunc = otherBinder;
  173. utils.getCurrentView().BindList( listName, lbl, objList );
  174. }
  175. /// <summary>
  176. /// 将对象列表绑定到模板
  177. /// </summary>
  178. /// <param name="listName">需要被绑定的列表名</param>
  179. /// <param name="lbl">对象在模板中的变量名</param>
  180. /// <param name="objList">对象的列表</param>
  181. /// <param name="otherBinder">附加的绑定器bindFunction( IBlock tpl, int id )</param>
  182. protected void bindList( String listName, String lbl, IList objList, bindFunction otherBinder ) {
  183. utils.getCurrentView().bindFunc = otherBinder;
  184. utils.getCurrentView().BindList( listName, lbl, objList );
  185. }
  186. /// <summary>
  187. /// 设置模板中表单提交的target
  188. /// </summary>
  189. /// <param name="url"></param>
  190. protected void target( String url ) {
  191. set( "ActionLink", url );
  192. }
  193. /// <summary>
  194. /// 设置模板中表单提交的target
  195. /// </summary>
  196. /// <param name="action"></param>
  197. protected void target( aAction action ) {
  198. set( "ActionLink", to( action ) );
  199. }
  200. /// <summary>
  201. /// 设置模板中表单提交的target
  202. /// </summary>
  203. /// <param name="action"></param>
  204. /// <param name="id"></param>
  205. protected void target( aActionWithId action, int id ) {
  206. set( "ActionLink", to( action, id ) );
  207. }
  208. //-------------------------------------- 控件 ----------------------------------------------
  209. /// <summary>
  210. /// 编辑器,工具栏只包括基本按钮
  211. /// </summary>
  212. /// <param name="propertyName">属性名称(也是编辑器名称)</param>
  213. /// <param name="propertyValue">需要被编辑的内容</param>
  214. /// <param name="height">编辑器高度(必须手动指定px单位)</param>
  215. protected void editor( String propertyName, String propertyValue, String height ) {
  216. if (ctx.route.isAdmin) {
  217. editorFull( propertyName, propertyValue, height );
  218. return;
  219. }
  220. Editor ed = Editor.NewOne( propertyName, propertyValue, height, sys.Path.Editor, MvcConfig.Instance.JsVersion, Editor.ToolbarType.Basic );
  221. ed.AddUploadUrl( ctx );
  222. set( "Editor", ed );
  223. }
  224. /// <summary>
  225. /// 编辑器,工具栏只包括基本按钮
  226. /// </summary>
  227. /// <param name="varName">模板中的变量名称</param>
  228. /// <param name="propertyName">需要编辑的属性名称</param>
  229. /// <param name="propertyValue">需要编辑的内容</param>
  230. /// <param name="height">编辑器高度(必须手动指定px单位)</param>
  231. protected void editor( String varName, String propertyName, String propertyValue, String height ) {
  232. editor( varName, propertyName, propertyValue, height, Editor.ToolbarType.Basic );
  233. }
  234. /// <summary>
  235. /// 编辑器
  236. /// </summary>
  237. /// <param name="varName">模板中的变量名称</param>
  238. /// <param name="propertyName">需要编辑的属性名称</param>
  239. /// <param name="propertyValue">需要编辑的内容</param>
  240. /// <param name="height">编辑器高度(必须手动指定px单位)</param>
  241. /// <param name="toolbar">工具栏类型:基本按钮或全部按钮</param>
  242. protected void editor( String varName, String propertyName, String propertyValue, String height, Editor.ToolbarType toolbar ) {
  243. String currentEditorKey = "currentEditor";
  244. List<String> editorList = ctx.GetItem( currentEditorKey ) as List<String>;
  245. if (editorList != null && editorList.Contains( propertyName )) throw new Exception( lang( "exEditorNameUnique" ) );
  246. Editor ed = Editor.NewOne( propertyName, propertyValue, height, sys.Path.Editor, MvcConfig.Instance.JsVersion, toolbar );
  247. ed.AddUploadUrl( ctx );
  248. if (editorList != null && editorList.Count > 0) ed.IsUnique = false;
  249. set( varName, ed );
  250. if (editorList == null) editorList = new List<string>();
  251. editorList.Add( propertyName );
  252. ctx.SetItem( currentEditorKey, editorList );
  253. }
  254. /// <summary>
  255. /// 编辑器,包括全部的工具栏
  256. /// </summary>
  257. /// <param name="propertyName">属性名称(也是编辑器名称)</param>
  258. /// <param name="propertyValue">需要被编辑的内容</param>
  259. /// <param name="height">编辑器高度(必须手动指定px单位)</param>
  260. protected void editorFull( String propertyName, String propertyValue, String height ) {
  261. Editor ed = Editor.NewOne( propertyName, propertyValue, height, sys.Path.Editor, MvcConfig.Instance.JsVersion, Editor.ToolbarType.Full );
  262. ed.AddUploadUrl( ctx );
  263. set( "Editor", ed );
  264. }
  265. /// <summary>
  266. /// 下拉控件(用数组填充)
  267. /// </summary>
  268. /// <param name="varName">控件名称</param>
  269. /// <param name="options">填充下拉框的字符数组</param>
  270. /// <param name="val">选定的值</param>
  271. protected void dropList( String varName, String[] options, Object val ) {
  272. set( varName, Html.DropList( options, varName, val ) );
  273. }
  274. /// <summary>
  275. /// 下拉控件(用 Dictionary 填充)
  276. /// </summary>
  277. /// <param name="varName">控件名称</param>
  278. /// <param name="dic">填充下拉框的Dictionary</param>
  279. /// <param name="val">选定的值</param>
  280. protected void dropList( string varName, Dictionary<string, string> dic, string val ) {
  281. set( varName, Html.DropList( dic, varName, val ) );
  282. }
  283. /// <summary>
  284. /// 下拉控件(用对象列表填充)
  285. /// </summary>
  286. /// <param name="varName">控件名称</param>
  287. /// <param name="list">填充下拉框的对象列表</param>
  288. /// <param name="nameValuePair">名值对,比如"Name=Id"表示用对象的属性Name填充选项的文本,用对象的属性Id填充选项的值</param>
  289. /// <param name="val">选定的值</param>
  290. protected void dropList( String varName, IList list, String nameValuePair, Object val ) {
  291. if (list == null || list.Count == 0) {
  292. set( varName, "" );
  293. return;
  294. }
  295. String[] arr = nameValuePair.Split( '=' );
  296. String dropString = Html.DropList( list, varName, arr[0], arr[1], val );
  297. set( varName, dropString );
  298. }
  299. /// <summary>
  300. /// 多个单选的列表(用字符数组填充)
  301. /// </summary>
  302. /// <param name="varName">控件名称</param>
  303. /// <param name="options">填充列表的字符数组</param>
  304. /// <param name="val">选定的值</param>
  305. protected void radioList( String varName, String[] options, Object val ) {
  306. set( varName, Html.RadioList( options, varName, val ) );
  307. }
  308. /// <summary>
  309. /// 多个单选的列表(用 Dictionary 填充)
  310. /// </summary>
  311. /// <param name="varName">控件名称</param>
  312. /// <param name="dic">填充列表的 Dictionary</param>
  313. /// <param name="val">选定的值</param>
  314. protected void radioList( string varName, Dictionary<string, string> dic, string val ) {
  315. set( varName, Html.RadioList( dic, varName, val ) );
  316. }
  317. /// <summary>
  318. /// 多个单选的列表(用对象列表填充)
  319. /// </summary>
  320. /// <param name="varName">控件名称</param>
  321. /// <param name="list">填充单选列表的对象列表</param>
  322. /// <param name="nameValuePair">名值对,比如"Name=Id"表示用对象的属性Name填充选项的文本,用对象的属性Id填充选项的值</param>
  323. /// <param name="val">选定的值</param>
  324. protected void radioList( String varName, IList list, String nameValuePair, Object val ) {
  325. String[] arr = nameValuePair.Split( '=' );
  326. set( varName, Html.RadioList( list, varName, arr[0], arr[1], val ) );
  327. }
  328. /// <summary>
  329. /// 多选框(用数组填充)
  330. /// </summary>
  331. /// <param name="varName">控件名称</param>
  332. /// <param name="options">填充列表的字符数组</param>
  333. /// <param name="val">选定的值,多个选值之间用英文逗号分开,比如 "2, 6, 13"</param>
  334. protected void checkboxList( String varName, String[] options, Object val ) {
  335. set( varName, Html.CheckBoxList( options, varName, val ) );
  336. }
  337. /// <summary>
  338. /// 多选框(用 Dictionary 填充)
  339. /// </summary>
  340. /// <param name="varName">控件名称</param>
  341. /// <param name="dic">填充列表的 Dictionary</param>
  342. /// <param name="val">选定的值,多个选值之间用英文逗号分开,比如 "2, 6, 13"</param>
  343. protected void checkboxList( string varName, Dictionary<string, string> dic, string val ) {
  344. set( varName, Html.CheckBoxList( dic, varName, val ) );
  345. }
  346. /// <summary>
  347. /// 多选框(用对象列表填充)
  348. /// </summary>
  349. /// <param name="varName">控件名称</param>
  350. /// <param name="list">填充多选列表的对象列表</param>
  351. /// <param name="nameValuePair">名值对,比如"Name=Id"表示用对象的属性Name填充选项的文本,用对象的属性Id填充选项的值</param>
  352. /// <param name="val">选定的值,多个选值之间用英文逗号分开,比如 "2, 6, 13"</param>
  353. protected void checkboxList( String varName, IList list, String nameValuePair, Object val ) {
  354. String[] arr = nameValuePair.Split( '=' );
  355. set( varName, Html.CheckBoxList( list, varName, arr[0], arr[1], val ) );
  356. }
  357. //-------------------------------------- 内部链接(快捷方式) ----------------------------------------------
  358. /// <summary>
  359. /// 链接到某个 action
  360. /// </summary>
  361. /// <param name="action"></param>
  362. /// <returns>返回一个链接</returns>
  363. public String to( aAction action ) {
  364. return this.Link.To( action );
  365. }
  366. /// <summary>
  367. /// 链接到某个 action
  368. /// </summary>
  369. /// <param name="action"></param>
  370. /// <param name="id"></param>
  371. /// <returns>返回一个链接</returns>
  372. public String to( aActionWithId action, int id ) {
  373. return this.Link.To( action, id );
  374. }
  375. /// <summary>
  376. /// 链接到某个 action,链接中不包含 appId 信息
  377. /// </summary>
  378. /// <param name="action"></param>
  379. /// <returns></returns>
  380. public String t2( aAction action ) {
  381. return this.Link.T2( action );
  382. }
  383. /// <summary>
  384. /// 链接到某个 action,链接中不包含 appId 信息
  385. /// </summary>
  386. /// <param name="action"></param>
  387. /// <param name="id"></param>
  388. /// <returns></returns>
  389. public String t2( aActionWithId action, int id ) {
  390. return this.Link.T2( action, id );
  391. }
  392. /// <summary>
  393. /// 设置当前 action 返回的内容(一旦设置,先前绑定的模板内容将被覆盖)
  394. /// </summary>
  395. /// <param name="content"></param>
  396. public void actionContent( String content ) {
  397. utils.setActionContent( content );
  398. }
  399. //-------------------------------------- 显示消息 ----------------------------------------------
  400. /// <summary>
  401. /// 根据模板显示提示信息。ajax情况不使用模板,只显示内容。
  402. /// </summary>
  403. /// <param name="msg"></param>
  404. public void echo( String msg ) {
  405. if (ctx.utils.isAjax) {
  406. echoText( msg );
  407. }
  408. else if (isFrame())
  409. showByMsgBoxTemplate( msg );
  410. else
  411. showEndByViewTemplate( msg );
  412. }
  413. /// <summary>
  414. /// 直接显示内容(不根据模板),然后结束
  415. /// </summary>
  416. /// <param name="msg"></param>
  417. public void echoText( String msg ) {
  418. actionContent( msg );
  419. ctx.utils.end();
  420. }
  421. /// <summary>
  422. /// 将json字符串直接输出到客户端(ContentType="application/json"),不再输出布局页面
  423. /// </summary>
  424. /// <param name="msg"></param>
  425. protected void echoJson( String jsonString ) {
  426. setJsonContentType();
  427. echoText( jsonString );
  428. }
  429. /// <summary>
  430. /// 将xml直接输出到客户端(ContentType="text/xml")
  431. /// </summary>
  432. /// <param name="xml"></param>
  433. protected void echoXml( String xml ) {
  434. ctx.web.ResponseContentType( "text/xml" );
  435. echoText( xml );
  436. }
  437. /// <summary>
  438. /// 将字符串 ok 显示到客户端
  439. /// </summary>
  440. protected void echoAjaxOk() {
  441. echoText( "ok" );
  442. }
  443. /// <summary>
  444. /// 显示错误信息并跳转到默认页。如果是ajax,输出错误信息的json格式。
  445. /// </summary>
  446. protected void echoError() {
  447. if (ctx.utils.isAjax) {
  448. echoJson( errors.ErrorsJson );
  449. }
  450. else {
  451. echoRedirect( errors.ErrorsHtml );
  452. ctx.utils.end();
  453. }
  454. }
  455. /// <summary>
  456. /// 显示错误信息。如果是ajax,输出错误信息的json格式。
  457. /// </summary>
  458. /// <param name="msg"></param>
  459. protected void echoError( String msg ) {
  460. errors.Add( msg );
  461. echoError();
  462. }
  463. /// <summary>
  464. /// 显示错误信息。如果是ajax,输出错误信息的json格式。
  465. /// </summary>
  466. /// <param name="result"></param>
  467. protected void echoError( Result result ) {
  468. errors.Join( result );
  469. echoError();
  470. }
  471. /// <summary>
  472. /// 显示 json 信息给客户端,提示是否 valid ,返回 {IsValid:true, Msg:'', Info:''}
  473. /// </summary>
  474. /// <param name="msg"></param>
  475. /// <param name="isValid"></param>
  476. /// <param name="otherInfo"></param>
  477. protected void echoJsonMsg( String msg, Boolean isValid, String otherInfo ) {
  478. echoJson( MvcUtil.renderValidatorJson( msg, isValid, otherInfo ) );
  479. }
  480. private void setJsonContentType() {
  481. ctx.web.ResponseContentType( "application/json" );
  482. }
  483. //----------------------------- 显示信息然后跳转 -----------------------------------
  484. /// <summary>
  485. /// 先显示提示信息(echo),然后跳转页面(redirect)。支持ajax。
  486. /// </summary>
  487. /// <param name="msg"></param>
  488. public void echoRedirect( String msg ) {
  489. // ajaxPostForm状态下,不跳转页面
  490. String returnUrl = ctx.utils.isAjax ? "" : getReturnUrl();
  491. returnUrl = clearLayoutInfo( returnUrl );
  492. echoRedirect( msg, returnUrl );
  493. }
  494. /// <summary>
  495. /// 显示信息,然后跳转到指定的action
  496. /// </summary>
  497. /// <param name="msg">显示的信息</param>
  498. /// <param name="action">跳转的目标action</param>
  499. public void echoRedirect( String msg, aAction action ) {
  500. echoRedirectPart( msg, to( action ), 9999 );
  501. }
  502. /// <summary>
  503. /// 显示信息,然后跳转到指定的url
  504. /// </summary>
  505. /// <param name="msg">显示的信息</param>
  506. /// <param name="url">跳转的目标网址</param>
  507. public void echoRedirect( String msg, String url ) {
  508. echoRedirectPart( msg, url, 9999 );
  509. }
  510. public void echoRedirectPart( String msg ) {
  511. String returnUrl = ctx.utils.isAjax ? "" : getReturnUrl();
  512. echoRedirectPart( msg, returnUrl );
  513. }
  514. /// <summary>
  515. /// 仅在当前局部中刷新
  516. /// </summary>
  517. /// <param name="msg"></param>
  518. /// <param name="url"></param>
  519. public void echoRedirectPart( String msg, String url ) {
  520. echoRedirectPart( msg, url, 0 );
  521. }
  522. /// <summary>
  523. /// 在指定范围的局部中刷新,从当前局部算起,倒着计数的layout中刷新:0、1、2、3、4
  524. /// </summary>
  525. /// <param name="msg"></param>
  526. /// <param name="url"></param>
  527. /// <param name="partNumber"></param>
  528. public void echoRedirectPart( String msg, String url, int partNumber ) {
  529. if (ctx.utils.isAjax) {
  530. String returnJson = "{\"IsValid\":true, \"IsParent\":true, \"PartNumber\":" + partNumber + ", \"Msg\":\"" + strUtil.Text2Html( msg ).Replace( "\"", "'" ) + "\", \"ForwardUrl\":\"" + url + "\"}";
  531. echoJson( returnJson );
  532. }
  533. else if (ctx.utils.isBox() || ctx.utils.isFrame()) {
  534. url = addFrameParams( url );
  535. forward( msg, url );
  536. }
  537. else {
  538. String str = "<script>$(document).ready( function() {wojilu.tool.forwardPart('" + url + "', " + partNumber + ");});</script><div class=\"forward\" id=\"forward\">" + msg + "</div>";
  539. showEndByViewTemplate( str, MvcConfig.Instance.GetForwardTemplatePath() );
  540. }
  541. ctx.utils.end();
  542. }
  543. private string clearLayoutInfo( string returnUrl ) {
  544. String[] arr = returnUrl.Split( '?' );
  545. if (arr.Length != 2) return returnUrl;
  546. String[] qItems = arr[1].Split( '&' );
  547. String url = arr[0] + "?";
  548. foreach (String item in qItems) {
  549. String[] arrItem = item.Split( '=' );
  550. if (isPartUrl( arrItem[0] )) continue;
  551. url += item + "&";
  552. }
  553. return url.TrimEnd( '&' ).TrimEnd( '?' );
  554. }
  555. private Boolean isPartUrl( String item ) {
  556. return item.Equals( "nolayout" ) || item.Equals( "frm" ) || item.Equals( "rd" );
  557. }
  558. // 表单下
  559. private String addFrameParamsWhenForm( String url ) {
  560. if (ctx.Post( "frm" ) != null && ctx.Post( "frm" ) == "true") {
  561. return addFrameParams( url );
  562. }
  563. return url;
  564. }
  565. /// <summary>
  566. /// (本方法不常用)将一段 html 字符串添加到父窗口的某个 elementID,一般客户端配合 ajaxUpdateForm 使用
  567. /// </summary>
  568. /// <param name="elementID"></param>
  569. /// <param name="htmlValue"></param>
  570. protected void echoHtmlTo( String elementID, String htmlValue ) {
  571. echoJsonMsg( htmlValue, true, elementID );
  572. }
  573. /// <summary>
  574. /// (用于弹窗中)显示提示信息,然后关闭弹窗,并刷新父页面
  575. /// </summary>
  576. /// <param name="msg"></param>
  577. protected void echoToParent( String msg ) {
  578. if (ctx.utils.isAjax) {
  579. String returnJson = "{\"IsValid\":true, \"Msg\":\"" + strUtil.Text2Html( msg ).Replace( "\"", "'" ) + "\", \"ForwardUrl\":\"\", \"IsParent\":true}";
  580. echoJson( returnJson );
  581. return;
  582. }
  583. String cmd = "wojilu.tool.getRootParent().wojilu.tool.reloadPage();";
  584. echoMsgAndJs( cmd, 500, msg );
  585. }
  586. protected void echoToParentPart( String msg ) {
  587. echoToParentPart( msg, "", 0 );
  588. }
  589. protected void echoToParentPart( String msg, String url ) {
  590. echoToParentPart( msg, url, 0 );
  591. }
  592. protected void echoToParentPart( String msg, String url, int partNumber ) {
  593. if (ctx.utils.isAjax) {
  594. String returnJson = "{\"IsValid\":true, \"Msg\":\"" + strUtil.Text2Html( msg ).Replace( "\"", "'" ) + "\", \"ForwardUrl\":\"" + url + "\", \"IsParent\":true}";
  595. echoJson( returnJson );
  596. return;
  597. }
  598. String cmd = "wojilu.tool.getBoxParent().wojilu.tool.forwardPart('" + url + "', " + partNumber + ");";
  599. echoMsgAndJs( cmd, 500, msg );
  600. }
  601. /// <summary>
  602. /// (用于弹窗中)显示提示信息,然后关闭弹窗,并让父页面跳转到指定url
  603. /// </summary>
  604. /// <param name="msg"></param>
  605. /// <param name="url"></param>
  606. protected void echoToParent( String msg, String url ) {
  607. echoToParentPart( msg, url, 9999 );
  608. }
  609. private void forward( String msg, String url ) {
  610. String str = "<script>$(document).ready( function() {wojilu.tool.forward('" + url + "');});</script><div class=\"forward\" id=\"forward\">" + msg + "</div>";
  611. showEndByViewTemplate( str, MvcConfig.Instance.GetForwardTemplatePath() );
  612. }
  613. private void forwardPage( String msg, String url ) {
  614. String str = "<script>$(document).ready( function() {wojilu.tool.forwardPage('" + url + "');});</script><div class=\"forward\" id=\"forward\">" + msg + "</div>";
  615. showEndByViewTemplate( str, MvcConfig.Instance.GetForwardTemplatePath() );
  616. }
  617. private void showEndByViewTemplate( String content ) {
  618. showEndByViewTemplate( content, MvcConfig.Instance.GetMsgTemplatePath() );
  619. }
  620. private void showByMsgBoxTemplate( String content ) {
  621. showEndByViewTemplate( content, MvcConfig.Instance.GetMsgBoxTemplatePath() );
  622. }
  623. private void showEndByViewTemplate( String content, String templatePath ) {
  624. ITemplate msgView = ctx.utils.getMsgTemplate( content, templatePath );
  625. actionContent( msgView.ToString() );
  626. ctx.utils.end();
  627. }
  628. //-------------------------------------- 直接跳转 ----------------------------------------------
  629. /// <summary>
  630. /// 自动跳转页面到来时的 url
  631. /// </summary>
  632. protected void redirect() {
  633. redirectUrl( getReturnUrl() );
  634. }
  635. /// <summary>
  636. /// 跳转页面到指定 action
  637. /// </summary>
  638. /// <param name="action"></param>
  639. public void redirect( aAction action ) {
  640. redirectUrl( Link.To( action ) );
  641. }
  642. /// <summary>
  643. /// 跳转页面到指定 action
  644. /// </summary>
  645. /// <param name="action"></param>
  646. /// <param name="id"></param>
  647. public void redirect( aActionWithId action, int id ) {
  648. redirectUrl( Link.To( action, id ) );
  649. }
  650. /// <summary>
  651. /// 跳转页面到指定 action
  652. /// </summary>
  653. /// <param name="action"></param>
  654. /// <param name="id"></param>
  655. public void redirect( String action, int id ) {
  656. redirectUrl( Link.To( base.GetType(), action, id ) );
  657. }
  658. /// <summary>
  659. /// 跳转页面到指定 url
  660. /// </summary>
  661. /// <param name="url"></param>
  662. public void redirectUrl( String url ) {
  663. if (ctx.utils.isAjax) {
  664. url = addFrameParamsWhenForm( url );
  665. String returnJson = "{\"IsValid\":true, \"ForwardUrl\":\"" + url + "\", \"Time\":0, \"PartNumber\":0}";
  666. echoJson( returnJson );
  667. }
  668. else if (isFrame()) {
  669. ctx.utils.end();
  670. ctx.utils.skipRender();
  671. url = addFrameParams( url );
  672. ctx.utils.clearResource();
  673. ctx.web.Redirect( url, false );
  674. }
  675. else if (hasNolayout()) {
  676. ctx.utils.end();
  677. ctx.utils.skipRender();
  678. url = addLayoutParams( url );
  679. ctx.utils.clearResource();
  680. ctx.web.Redirect( url, false );
  681. }
  682. else {
  683. ctx.utils.end();
  684. ctx.utils.skipRender();
  685. ctx.utils.clearResource();
  686. ctx.web.Redirect( url, false );
  687. }
  688. }
  689. private Boolean hasNolayout() {
  690. return ctx.utils.getNoLayout() > 0 || referrerHasNolayout();
  691. }
  692. private Boolean referrerHasNolayout() {
  693. if (ctx.web.PathReferrer == null) return false;
  694. return ctx.web.PathReferrer.IndexOf( "nolayout" ) > 0;
  695. }
  696. private Boolean isFrame() {
  697. return ctx.utils.isFrame();
  698. }
  699. /// <summary>
  700. /// 向客户端返回没有权限的信息(401 Unauthorized),同时跳转到登录页面
  701. /// </summary>
  702. public void redirectLogin() {
  703. ctx.utils.end();
  704. ctx.utils.skipRender();
  705. ctx.utils.clearResource();
  706. ctx.web.ResponseStatus( HttpStatus.Unauthorized_401 );
  707. }
  708. // 如果 url 中已经有 frm=true了,则直接返回
  709. private String addFrameParams( String url ) {
  710. String frmStr = "frm=true";
  711. if (url.IndexOf( frmStr ) > 0) return url;
  712. return appendParam( url, frmStr );
  713. }
  714. private string addLayoutParams( string url ) {
  715. if (url.IndexOf( "nolayout" ) > 0) return url;
  716. int nolayout = ctx.utils.getNoLayout();
  717. if (nolayout <= 0) nolayout = getReferrerNolayout();
  718. String param = "nolayout=" + nolayout;
  719. return appendParam( url, param );
  720. }
  721. private int getReferrerNolayout() {
  722. String rUrl = ctx.web.PathReferrer;
  723. String[] arrItems = rUrl.Split( '?' );
  724. if (arrItems.Length != 2) return 0;
  725. String[] queryItems = arrItems[1].Split( '&' );
  726. foreach (String item in queryItems) {
  727. if (item.StartsWith( "nolayout=" )) {
  728. return cvt.ToInt( strUtil.TrimStart( item, "nolayout=" ) );
  729. }
  730. }
  731. return 0;
  732. }
  733. private String appendParam( String url, String param ) {
  734. if (url.IndexOf( '?' ) < 0) return url + "?" + param;
  735. if (url.EndsWith( "?" )) return url + param;
  736. if (url.EndsWith( "&" )) return url + param;
  737. return url + "&" + param;
  738. }
  739. //-------------------------------------- ajax返回值 ----------------------------------------------
  740. private void echoMsgAndJs( String cmd, int msTime, String msg ) {
  741. String tcall = "setTimeout( function(){" + cmd + ";wojilu.tool.getBoxParent().wojilu.ui.box.hideBox();}, " + msTime + " );";
  742. String content = "$(document).ready( function() { " + tcall + " });";
  743. content = String.Format( "<script type=\"text/javascript\">{0}</script>", content ) + msg;
  744. showByMsgBoxTemplate( content );
  745. }
  746. private String getReturnUrl() {
  747. if (strUtil.HasText( ctx.web.PathReferrer ))
  748. return ctx.web.PathReferrer;
  749. return ctx.url.AppPath;
  750. }
  751. //-------------------------------------- 绑定(加载)局部页面内容 ----------------------------------------------
  752. /// <summary>
  753. /// 将某 action 的内容加载到指定位置
  754. /// </summary>
  755. /// <param name="sectionName">需要加载内容的位置</param>
  756. /// <param name="action">被加载的 action</param>
  757. protected void load( String sectionName, aAction action ) {
  758. set( sectionName, loadHtml( action ) );
  759. }
  760. /// <summary>
  761. /// 获取某 action 的内容
  762. /// </summary>
  763. /// <param name="controller"></param>
  764. /// <param name="action"></param>
  765. /// <returns></returns>
  766. public String loadHtml( String controller, String action ) {
  767. return ControllerRunner.Run( ctx, controller, action );
  768. }
  769. /// <summary>
  770. /// 获取某 action 的内容
  771. /// </summary>
  772. /// <param name="controller"></param>
  773. /// <param name="action"></param>
  774. /// <param name="id"></param>
  775. /// <returns></returns>
  776. public String loadHtml( String controller, String action, int id ) {
  777. return ControllerRunner.Run( ctx, controller, action, id );
  778. }
  779. // TODO 在被load的action中,使用showEnd无效
  780. /// <summary>
  781. /// 获取某 action 的内容
  782. /// </summary>
  783. /// <param name="action"></param>
  784. /// <returns></returns>
  785. public String loadHtml( aAction action ) {
  786. String result;
  787. if (isSameType( action.Method )) {
  788. String actionName = action.Method.Name;
  789. Template originalView = utils.getCurrentView();
  790. setView( action.Method );
  791. action();
  792. Template resultView = utils.getCurrentView();
  793. utils.setCurrentView( originalView );
  794. result = resultView.ToString();
  795. }
  796. else {
  797. // 如果继承
  798. String actionName = action.Method.Name;
  799. ControllerBase otherController = ControllerFactory.FindController( action.Method.DeclaringType, ctx );
  800. otherController.view( actionName );
  801. otherController.utils.runAction( actionName );
  802. result = otherController.utils.getCurrentView().ToString();
  803. //result = otherController.utils.getActionResult();
  804. // 如果没有继承
  805. //result = ControllerRunner.Run( action, ctx );
  806. }
  807. return result;
  808. }
  809. /// <summary>
  810. /// 获取某 action 的内容
  811. /// </summary>
  812. /// <param name="action"></param>
  813. /// <param name="id"></param>
  814. /// <returns></returns>
  815. public String loadHtml( aActionWithId action, int id ) {
  816. String result;
  817. if (isSameType( action.Method )) {
  818. String actionName = action.Method.Name;
  819. Template originalView = utils.getCurrentView();
  820. setView( action.Method );
  821. action( id );
  822. Template resultView = utils.getCurrentView();
  823. utils.setCurrentView( originalView );
  824. result = resultView.ToString();
  825. }
  826. else {
  827. //ControllerBase targetController = action.Target as ControllerBase;
  828. //ControllerFactory.InjectController( targetController, ctx );
  829. //targetController.view( action.Method.Name );
  830. //action( id );
  831. //result = targetController.utils.getCurrentView().ToString();
  832. result = ControllerRunner.Run( ctx, action, id );
  833. }
  834. return result;
  835. }
  836. /// <summary>
  837. /// 运行其他 action,并将运行结果作为当前 action 的内容
  838. /// </summary>
  839. /// <param name="action"></param>
  840. protected void run( aAction action ) {
  841. if (ctx.utils.isAjax) {
  842. if (ctx.HasErrors)
  843. echoError();
  844. else
  845. echoAjaxOk();
  846. return;
  847. }
  848. if (isSameType( action.Method )) {
  849. setView( action.Method );
  850. action();
  851. }
  852. else {
  853. //ControllerBase mycontroller = ControllerFactory.FindController( action.Method.DeclaringType, ctx );
  854. //mycontroller.view( action.Method.Name );
  855. //action.Method.Invoke( mycontroller, null );
  856. //actionContent( mycontroller.utils.getActionResult() );
  857. actionContent( ControllerRunner.Run( ctx, action ) );
  858. }
  859. }
  860. /// <summary>
  861. /// 运行其他 action,并将运行结果作为当前 action 的内容
  862. /// </summary>
  863. /// <param name="action"></param>
  864. /// <param name="id"></param>
  865. protected void run( aActionWithId action, int id ) {
  866. if (ctx.utils.isAjax) {
  867. if (ctx.HasErrors)
  868. echoError();
  869. else
  870. echoAjaxOk();
  871. return;
  872. }
  873. if (isSameType( action.Method )) {
  874. setView( action.Method );
  875. action( id );
  876. }
  877. else {
  878. //ControllerBase mycontroller = ControllerFactory.FindController( action.Method.DeclaringType, ctx );
  879. //mycontroller.view( action.Method.Name );
  880. //action.Method.Invoke( mycontroller, new object[] { id } );
  881. //actionContent( mycontroller.utils.getActionResult() );
  882. actionContent( ControllerRunner.Run( ctx, action, id ) );
  883. }
  884. }
  885. /// <summary>
  886. /// 运行其他 action,并将运行结果作为当前 action 的内容
  887. /// </summary>
  888. /// <param name="controllerType">被运行的 action 所属的 controller 类型</param>
  889. /// <param name="actionName">action 名称</param>
  890. /// <param name="args">需要的参数</param>
  891. protected void run( String controllerFullTypeName, String actionName, params object[] args ) {
  892. Type controllerType = ObjectContext.Instance.TypeList[controllerFullTypeName];
  893. if (controllerType == base.GetType()) {
  894. view( actionName );
  895. MethodInfo method = base.GetType().GetMethod( actionName );
  896. if (method == null) {
  897. throw new Exception( "action " + wojilu.lang.get( "exNotFound" ) );
  898. }
  899. else {
  900. method.Invoke( this, args );
  901. }
  902. }
  903. else {
  904. actionContent( ControllerRunner.Run( ctx, controllerFullTypeName, actionName, args ) );
  905. }
  906. }
  907. private Boolean isSameType( MethodInfo method ) {
  908. Boolean result = this.GetType() == method.DeclaringType || this.GetType().IsSubclassOf( method.DeclaringType );
  909. return result;
  910. }
  911. private void setView( MethodInfo method ) {
  912. if (this.GetType().IsSubclassOf( method.DeclaringType )) {
  913. String filePath = MvcUtil.getParentViewPath( method, ctx.route.getRootNamespace( method.DeclaringType.FullName ) );
  914. this.utils.setCurrentView( this.utils.getTemplateByFileName( filePath ) );
  915. }
  916. else {
  917. view( method.Name );
  918. }
  919. }
  920. //------------------------------------------------------------------------
  921. /// <summary>
  922. /// 从核心语言包(core.config)中获取多国语言的值
  923. /// </summary>
  924. /// <param name="key"></param>
  925. /// <returns></returns>
  926. protected String lang( String key ) {
  927. return wojilu.lang.get( key );
  928. }
  929. /// <summary>
  930. /// 从各 app 的语言包中获取多国语言的值
  931. /// </summary>
  932. /// <param name="key"></param>
  933. /// <returns></returns>
  934. public String alang( String key ) {
  935. return utils.getAppLang() == null ? null : utils.getAppLang().get( key );
  936. }
  937. }
  938. }