ASP.NET (transfer) saved in the multi-level directory in WinForm

xiaoxiao2021-03-06  103

For more than half a year, a simple example of embedding ASP.NET in the WinForm program has been written.

"Embed an ASP.NET in the WinForm program." Because it is a test-based job, it is said that the SIMPLEWORKERREQUEST that is lazy directly uses the system to complete the processing of the ASP.NET page request. Using the own tool class is implemented, it is simple, but is limited by the system's various functional restrictions, such as behind the latter, it is impossible to directly handle the multi-level directory issues. (If the virtual directory is "/", the "/HELP /ABOUT.ASPX" page request cannot be processed)

For this type of demand, a best implementation instance is www.asp.net

Cassini. This example completely demonstrates how to implement a simple web server function that supports ASP.NET and is made by Borland's Delphi.NET, which is used as a WEB server. Although only tens of K's source code, although the sparrow is small, it is still very worth seeing. But because Cassini is designed to handle web services, it is necessary to do some customization to meet our needs on the basis of understanding its structure.

Let's take a look at the program structure of Cassini.

Similar to the structure used in the foregoing example, Cassini includes several main parts of the interface (Server), Server, host, host (host), and several tool classes such as Connection, completes Web Request parsing and answering function.

The overall workflow chart is as follows:

The following is the program code: ----- [1] ------------- [2] -------- | admin | ---> | CassiniForm | ----> | Server | ------- ---------- -------- | [3] V -------- [4] ---- | Client | ----> | Host | -------- --- --- ^ | [5] | V | ------------ [6] ------- [7] | | Connection | -> | Request | - | ---------- --------- | [7] ----------- -----------------------------

[1] Cassini's Manager (Admin) first passed the configuration information such as the web server port, page physical catalog, and virtual directory through the interface of CassiniForm;

[2] then construct a Server object with configuration information, and call the server.start method to start the web server; the following is program code: public class cassiniform: form {private void start () {// ... try {_server = new Cassini .Server (portnumber, _appath); _server.start ();} catch {// Display error message} // ...}}

[3] Server objects are created, will get the registry configuration of the ASP.NET will be generated when it is created. This work is done through the Server.getInstallPathandconfigureASpnetifNeeded method. The working principle is to get the appropriate ASP.NET version through the version of the assembly (system.web.dll) of HTTPRuntime; then query the installation path of the correct ASP.NET under HKEY_LOCAL_MACHINESOFTWAREMICROSOFTASP.NET from the registry; if it is returned Otherwise, according to the version of System.Web.dll, and HKEY_LOCAL_MACHINESOFTWAREMICROSOFT.NET FRAMEWORK. NET Framework is dynamically constructed to dynamically construct a suitable ASP.NET registry configuration. The reason for this work is that ASP.NET can be manually logged out by manually using ASPNET_REGIIS.EXE, running the web server that supports ASP.NET, and must have a suitable setting.

After completing the configuration and the ASP.NET installation path, Server will establish and configure the host object as a host of ASP.NET.

The following program code is: public class Server: MarshalByRefObject {private void CreateHost () {_host = (Host) ApplicationHost.CreateApplicationHost (typeof (Host), _virtualPath, _physicalPath); _host.Configure (this, _port, _virtualPath, _physicalPath, _installPath (} Public void start () {i (_host! = Null) _host.start ();}}

[4] Host class as an ASP.NET host class, mainly completing three parts: configuring the Runtime Environment of ASP.NET, responding to Web page requests initiated by the client (client), and judging the validity of the client request.

The main job of configuring the runtime environment of ASP.NET is to obtain sufficient configuration information for the execution of ASP.NET and the rear request validity. For example, the web service port, page virtual path, page physical path, and ASP.NET program installation path, and the ASP.NET program installation path, and Host's virtual and physical paths of ASP.NET client scripts calculated according to this information. In addition, the AppDomain.Domainunload where the thread is located, and the web service is automatically terminated when the web server is stopped.

The Web Page Request function initiated by the client (Client) is done by establishing a web service TCP port specified by the Socket listening Server object. Host.Start method creates Socket and invokes the host.onstart method through the thread pool in the back desk listening request; Host.onStart method After receiving the web request, call the Host.onSocketAccept method to complete the request response work by the thread pool; Host .OncketAccept is responsible for establishing a Connection object when processing a web request, and further calling the Connection.ProcessOneRequest method to handle web request. Although Host does not use complex request allocation algorithms, because of the flexible use of the thread pool, it is a good example of the use of the thread pool completely from the restriction of the bottleneck. The following program code: internal class Host: MarshalByRefObject {public void Start () {if (_started) throw new InvalidOperationException (); // establish Socket listening Web service port _socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType .Tcp); _socket.Bind (new IPEndPoint (IPAddress.Any, _port)); _socket.Listen ((int) SocketOptionName.MaxConnections); _started = true; ThreadPool.QueueUserWorkItem (_onStart); //} asynchronous call by a thread pool private void OnStart (Object unused) {while (_started) {try {Socket socket = _socket.Accept (); // responding to client requests ThreadPool.QueueUserWorkItem (_onSocketAccept, socket); // call through an asynchronous thread pool} catch {thread .Sleep (100);}} _stopped = true;} private void OnSocketAccept (Object acceptedSocket) {Connection conn = new Connection (this, (Socket) acceptedSocket); conn.ProcessOneRequest (); //}} client request

Finally, it is determined that the functionality of the validity of the client request is to pass the three overloaded Host.isvirtualPathinapp methods, and the validity of the request is provided to determine the validity of the request when the client requests, and discusses the connection of the request. .

[5] HOST When establishing a Connection object and calls its ProcessOnRequest method, the Connection object will first wait for the client request data (WaitforRequestBytes), then create the request object, and call the Request.Process method to process the request. And itself, by a bunch of WAITXXX functions, supports the Request class.

The following is program code: Internal class connection {public void processONEREQUEST () {// Wait for at Least Some INPUT IF (WaitforRequestBytes () == 0) {// Waiting for the client request data WriteErrorAndClose (400); // Send http 400 Error to the client Return;} Request request = new request (_host, this); Request.Process ();} private int waitforrequestBytes () {Int availbytes = 0; try {ket.available == 0) {/ / Polket.poll (100000 / * 100ms * /, selectmode.selectread); // Waiting for the client data 100ms time if (_Socket.available == 0 && _socket.connected) _socket.poll (10000000 / * 10sec * /, selectmode.selectread;} ​​availbytes = _socket.available;} catch {} return availbytes;} [6] request After receiving the Connection request, read the request content from the client, and according to the HTTP protocol analysis. Because this article is not an analysis of the HTTP protocol, this part of the code is not discussed in detail.

After the Request.ParsequestLine function analysis HTTP request obtains the request page path, the previously mentioned Host.isvirtualPathinapp function is called to determine if the path is at the virtual path provided by the web server, and returns this virtual path to the ASP.NET customer End script. If the virtual path of the web request is ended in "/", call the Request.ProcessDirectoryListingRequest method to return to the column directory; otherwise call the httpruntime.processRequest method to complete the actual ASP.NET request processing.

HTTPRuntime uses IOC's policy to get the final page with the unified interface provided by the Request's base class HttpWorkerRequest. The maximum difference between SimpleWorkerRequest implementation used in the previous article is that Request.mAppath has completed a more complete virtual directory to physical directory mapping mechanism.

SimpleWorkerRequest.mappath implementation is relatively simple:

The following program code is: public override string SimpleWorkerRequest.MapPath (string path) {if {return null;} string physPath = null; string appPhysPath = this._appPhysPath.Substring (0, (this._appPhysPath (this._hasRuntimeInfo!). Length - 1)); // Remove the end of the tail clot bar IF ((PATH == Null) || (path.length == 0)) || path.equals ("/")) {physpath = appphyspath;} (path.StartsWith (this._appVirtPath)) {physPath = appPhysPath path.Substring (this._appVirtPath.Length) .Replace ( '/', '/');} InternalSecurityPermissions.PathDiscovery (physPath) .Demand (); return Physpath;} Request.mAppath is relatively improved, considering a lot of SimpleWorkerRequest unable to handle, making Request's adaptability is stronger.

The following is program code: public override string request.mappath (string path) {string mappedPath = string.empty; if (path == null || path.length == 0 || path.equals ("/")) { // asking for the site root if (_host.virtualpath == ") {// app at the site root mappedPath = _host.physicalPath;} else {// unknown site root - don't point to app root to avoid double config inclusion mappedPath = Environment.SystemDirectory;}} else if (_host.IsVirtualPathAppPath (path)) {// application path mappedPath = _host.PhysicalPath;} else if (_host.IsVirtualPathInApp (path)) {// inside app but not the app path itself mappedPath = _host.PhysicalPath path.Substring (_host.NormalizedVirtualPath.Length);} else {// outside of app - make relative to app path if (path.StartsWith ( "/")) mappedPath = _host .PhysicalPath path.substring (1); else mappedPath = _host.physicalPath path;} mappedPath = mappedPath.Repped ('/', '/'); if (mappedpath.en); DSWITH ("/") &&! mappedpath.endswith (": /")) mappedpath = mappedpath.substring (0, mappedpath.length-1); return mappedPath;} About Cassini further discussion, you can refer to www.asp.net Up

Discussion special edition.

[7] After HTTRUNTIME completes the specific ASP.NET page processing, return the page results to the client through the Request.sendResponseFromxxx series function.

Although the SimpleWorkerRequest.mappath method is simple, it is theoretically to process the multi-level directory. When using SimpleWorkerRequest, the nested directory cannot be processed because SimpleWorkerRequest is incorrectly decomposed in the constructor's virtual directory and other information.

The two constructor of SimpleWorkerRequest calls the extractPagePathInfo method to further decompose the page path after saving the request page virtual path (such as "/ Help/about.aspx").

The following is program code: private void SimpleWorRequest.extractPagePathinfo () {int idx = this._page.indexof ('/'); if (idx> = 0) {this._pathinfo = this._page.substring (IDX); this ._page = this._page.substring (0, IDX);}} this._pathinfo is the storage field provided to implement HttpWorkerRequest.getPathInfo. GetPathInfo will return to the path information after the page in the URL, such as "path / virdir / page.html / tail" will return "/ tail". Many HTTP client programs, such as WebAction in Delphi, use this path information, after the web page or ISAPI level, request distribution again. However, because SimpleWorkerRequest implementations or designed restrictions, multi-level URL errors similar to "/ HELP /ABOUT.ASPX" will be cut off when processing PathInfo. The this.

After you know this principle, you can modify the SimpleWorkerRequest, and override several ways affected by the extractPagePathInfo, you can complete support for the multi-level directory structure. If further mapping support is required, such as the multiple virtual subdirectories, you can refer to the Cassini Request to implement mappath.

The following is a program code: public class Request: SimpleWorkerRequest {private string _appPhysPath; private string _appVirtPath; private string _page; private string _pathInfo; public Request (string page, string query, TextWriter output): base (page, query, output) { THIS_APPPHYSPATH = Thread.getdomain (). getData (". AppPath"). Tostring (); this._appvirtpath = thread.getdomain (). getData (". hostingvirtualpath"). TOSTRING (); this._page = Page; // TODO: further resolved Path Info} public override string getPathInfo () from the page {if (this._pathInfo == null) {return string.Empty;} return this._pathInfo;} private string GetPathInternal (bool includePathInfo) {string path = (_appVirtPath.Equals ( "/") _page:? _appVirtPath _page); if (! includePathInfo && (_pathInfo = null)) {return path this._pathInfo;} else {return path;}} public override string GetUriPath () {Return getPathinternal (True);} public override string getFilePath () {RE Turn getPathinternal (false);} public override string getrawurl () {string query = this.getQueryString (); if (Query! = null) && (query.length> 0)) {RETURN GETPATHINTERNAL (TRUE) "?" query;} else {return GetPathInternal (true);}} public override string GetFilePathTranslated () {return _appPhysPath _page.Replace ( '/', '/');} public override string MapPath (string path) {string physPath = NULL; IF ((PATH == Null) || (path.length == 0)) || path.equals ("/")) {physpath = this._appphyspath;

转载请注明原文地址:https://www.9cbs.com/read-122205.html

New Post(0)