post 是 http 协议规定的方法,在使用 html 时,post 是 form 标签提交时的可用选项,另一个选项是 get。这是与 asp.net 或者 php 等服务端脚本技术无关的对于 asp.net mvc,请求会通过路由映射到 controller.action 上,当然还可以做稍微细致一点的控制,比如让 post 请求路由到带有 [HttpPost] 属性的 action 上,这个相对比较直观。对于 asp.net webform,aspx 页面在生成 html 时会做些处理,点击按钮后,form 携带着许多额外的信息提交到服务端,服务端利用这些信息,还原页面对象模型,模拟出类似桌面编程的事件模型,比如单击事件是哪个按钮引发的,页面的整个状态是什么样的。话说这是一种相当丑陋的编程模型,MS 的初衷是简化开发,让 web 开发者想开发桌面系统一样基于事件概念进行编程。然而这种和 http 无连接天性对着干的结果是处理过程异常繁杂。你非要对暗藏在后面的整个过程有深入了解之后才能写出像样的程序。当 ajax 浪潮袭来的时候,对 html 代码做了很多侵入性处理的 webform 十分不适应,混乱的 id 让人抓狂,微软推出的 ajax 工具功能既不强大,也不方便。于是就有了后来的 asp.net mvc。P哥列出的技术细节我想是没必要深究的。
b/s程序 ,一般点击一个button 提交的话,会在url后边加一个button=按钮name参数的
服务器端会根据这个参数寻到相应的处理函数。
{
try
{
HttpContext context = this.Context;
string str = null;
if (includeStagesBeforeAsyncPoint)
{
if (this.IsInAspCompatMode)
{
AspCompatApplicationStep.OnPageStartSessionObjects();
}
if (this.PageAdapter != null)
{
this._requestValueCollection = this.PageAdapter.DeterminePostBackMode();
if (this._requestValueCollection != null)
{
this._unvalidatedRequestValueCollection = this.PageAdapter.DeterminePostBackModeUnvalidated();
}
}
else
{
this._requestValueCollection = this.DeterminePostBackMode();
if (this._requestValueCollection != null)
{
this._unvalidatedRequestValueCollection = this.DeterminePostBackModeUnvalidated();
}
}
string callbackControlID = string.Empty;
if (this.DetermineIsExportingWebPart())
{
if (!RuntimeConfig.GetAppConfig().WebParts.EnableExport)
{
throw new InvalidOperationException(SR.GetString("WebPartExportHandler_DisabledExportHandler"));
}
str = this.Request.QueryString["webPart"];
if (string.IsNullOrEmpty(str))
{
throw new InvalidOperationException(SR.GetString("WebPartExportHandler_InvalidArgument"));
}
if (string.Equals(this.Request.QueryString["scope"], "shared", StringComparison.OrdinalIgnoreCase))
{
this._pageFlags.Set(4);
}
string str3 = this.Request.QueryString["query"];
if (str3 == null)
{
str3 = string.Empty;
}
this.Request.QueryStringText = str3;
context.Trace.IsEnabled = false;
}
if (this._requestValueCollection != null)
{
if (this._requestValueCollection["__VIEWSTATEENCRYPTED"] != null)
{
this.ContainsEncryptedViewState = true;
}
callbackControlID = this._requestValueCollection["__CALLBACKID"];
if ((callbackControlID != null) && (this._request.HttpVerb == HttpVerb.POST))
{
this._isCallback = true;
}
else if (!this.IsCrossPagePostBack)
{
VirtualPath path = null;
if (this._requestValueCollection["__PREVIOUSPAGE"] != null)
{
try
{
path = VirtualPath.CreateNonRelativeAllowNull(DecryptString(this._requestValueCollection["__PREVIOUSPAGE"], Purpose.WebForms_Page_PreviousPageID));
}
catch
{
this._pageFlags[8] = true;
}
if ((path != null) && (path != this.Request.CurrentExecutionFilePathObject))
{
this._pageFlags[8] = true;
this._previousPagePath = path;
}
}
}
}
if (this.MaintainScrollPositionOnPostBack)
{
this.LoadScrollPosition();
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Begin PreInit");
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_PRE_INIT_ENTER, this._context.WorkerRequest);
}
this.PerformPreInit();
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_PRE_INIT_LEAVE, this._context.WorkerRequest);
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End PreInit");
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Begin Init");
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_INIT_ENTER, this._context.WorkerRequest);
}
this.InitRecursive(null);
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_INIT_LEAVE, this._context.WorkerRequest);
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End Init");
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Begin InitComplete");
}
this.OnInitComplete(EventArgs.Empty);
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End InitComplete");
}
if (this.IsPostBack)
{
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Begin LoadState");
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_VIEWSTATE_ENTER, this._context.WorkerRequest);
}
this.LoadAllState();
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_VIEWSTATE_LEAVE, this._context.WorkerRequest);
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End LoadState");
this.Trace.Write("aspx.page", "Begin ProcessPostData");
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_POSTDATA_ENTER, this._context.WorkerRequest);
}
this.ProcessPostData(this._requestValueCollection, true);
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_POSTDATA_LEAVE, this._context.WorkerRequest);
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End ProcessPostData");
}
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Begin PreLoad");
}
this.OnPreLoad(EventArgs.Empty);
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End PreLoad");
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Begin Load");
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_ENTER, this._context.WorkerRequest);
}
this.LoadRecursive();
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_LEAVE, this._context.WorkerRequest);
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End Load");
}
if (this.IsPostBack)
{
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Begin ProcessPostData Second Try");
}
this.ProcessPostData(this._leftoverPostData, false);
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End ProcessPostData Second Try");
this.Trace.Write("aspx.page", "Begin Raise ChangedEvents");
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_POST_DATA_CHANGED_ENTER, this._context.WorkerRequest);
}
this.RaiseChangedEvents();
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_POST_DATA_CHANGED_LEAVE, this._context.WorkerRequest);
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End Raise ChangedEvents");
this.Trace.Write("aspx.page", "Begin Raise PostBackEvent");
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_RAISE_POSTBACK_ENTER, this._context.WorkerRequest);
}
this.RaisePostBackEvent(this._requestValueCollection);
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_RAISE_POSTBACK_LEAVE, this._context.WorkerRequest);
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End Raise PostBackEvent");
}
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Begin LoadComplete");
}
this.OnLoadComplete(EventArgs.Empty);
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End LoadComplete");
}
if (this.IsPostBack && this.IsCallback)
{
this.PrepareCallback(callbackControlID);
}
else if (!this.IsCrossPagePostBack)
{
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Begin PreRender");
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_PRE_RENDER_ENTER, this._context.WorkerRequest);
}
this.PreRenderRecursiveInternal();
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_PRE_RENDER_LEAVE, this._context.WorkerRequest);
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End PreRender");
}
}
}
if ((this._legacyAsyncInfo == null) || this._legacyAsyncInfo.CallerIsBlocking)
{
this.ExecuteRegisteredAsyncTasks();
}
this.ValidateRawUrlIfRequired();
if (includeStagesAfterAsyncPoint)
{
if (this.IsCallback)
{
this.RenderCallback();
}
else if (!this.IsCrossPagePostBack)
{
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Begin PreRenderComplete");
}
this.PerformPreRenderComplete();
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End PreRenderComplete");
}
if (context.TraceIsEnabled)
{
this.BuildPageProfileTree(this.EnableViewState);
this.Trace.Write("aspx.page", "Begin SaveState");
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_SAVE_VIEWSTATE_ENTER, this._context.WorkerRequest);
}
this.SaveAllState();
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_SAVE_VIEWSTATE_LEAVE, this._context.WorkerRequest);
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End SaveState");
this.Trace.Write("aspx.page", "Begin SaveStateComplete");
}
this.OnSaveStateComplete(EventArgs.Empty);
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End SaveStateComplete");
this.Trace.Write("aspx.page", "Begin Render");
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_RENDER_ENTER, this._context.WorkerRequest);
}
if (str != null)
{
this.ExportWebPart(str);
}
else
{
this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output));
}
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_RENDER_LEAVE, this._context.WorkerRequest);
}
if (context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "End Render");
}
this.CheckRemainingAsyncTasks(false);
}
}
}
catch (ThreadAbortException exception)
{
HttpApplication.CancelModuleException exceptionState = exception.ExceptionState as HttpApplication.CancelModuleException;
if (((!includeStagesBeforeAsyncPoint || !includeStagesAfterAsyncPoint) || ((this._context.Handler != this) || (this._context.ApplicationInstance == null))) || ((exceptionState == null) || exceptionState.Timeout))
{
this.CheckRemainingAsyncTasks(true);
throw;
}
this._context.ApplicationInstance.CompleteRequest();
ThreadResetAbortWithAssert();
}
catch (ConfigurationException)
{
throw;
}
catch (Exception exception3)
{
PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_DURING_REQUEST);
PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_TOTAL);
if (!this.HandleError(exception3))
{
throw;
}
}
}大致来说,首先通过 InitRecursive 方法重建那些在设计页面上标记的控件树,然后通过 LoadAllState 把上一次页面输出html时保存到页面上的ViewState重新加载到内存,然后通过 LoadRecursive 方法重建上一次页面输出html时的控件树(同时asp.net给你自动填入ViewState值到各个控件),然后通过 ProcessPostData 来处理客户端提交的新值(此时就记录下哪些控件需要随后触发 xxxDataChanged 类似事件),然后调用 RaiseChangedEvents 来触发这些事件,然后调用 RaisePostbackEvent 调用客户端专门要求触发的控件事件,然后调用 SaveAllState 将各个控件的ViewState收集起来,最后调用 RenderControl 将整个控件生成html输出给客户端。Button有两种。一种是设置了 UserSubmitBehavior 属性为 true 的(默认值),它使用传统的web页面的机制,通过 RaiseChangedEvents 来触发(浏览器会给这个按钮的value赋值,从而触发服务器端)。另一种是设置这个属性为false的,那么asp.net会使用其 IPostbackEventHandler 机制,输出脚本让客户端通过 __POstback(....) 来触发,从而回发到服务器端会在 RaisePostbackEvents 过程中被触发。