开发者

How to asynchronously call the function in asp.net ? or any other solution to reach the goal?

The goal of the function is to fill the from (from 3rd party website) and click the submit button and gets the html source of the submitted result page. This task needs to be done on click event of the button in asp.net. If the function returns true, do some sql tasks at the end. I read about the Asynchronous Handler in asp.net but really beginner of that and not sure what a best solution is to simulate this type of task in asp.net.

Protected Sub lbtnSave_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles lbtnSave.Click
             If  CrawlWebSite() then
                'Save
             End If
         End Sub

Private Function CrawlWebSite() As Boolean
            Dim objBrowser = CreateObject("InternetExplorer.Application")
            Dim url As String = "https://test.com/Search.do?subAction=reset&searchType=ind"
            With objBrowser
                .navigate(url)
                System.Threading.Thread.Sleep(1000)

                Dim StartTime As DateTime
                Dim ElapsedTime As TimeSpan
                Dim bLong As Boolean = False
                StartTime = Now
                Do While .busy = True
                    ElapsedTime = Now().Subtract(StartTime)
                    If (ElapsedTime.TotalSeconds Mod 60) >= 55 Then
                        bLong = True
                        Exit Do
                    End If
                    System.Threading.Thread.Sleep(1000)
     开发者_StackOverflow社区           Loop

                If bLong = True Then
                    PageName.Alert(Page, "There is a delay retrieving the website for checking NPI. Please try again.")
                    Return False
                End If

                .document.getElementById("lastname").Value = txtLastName.Text.Trim
                .document.getElementById("searchNpi").Value = txtUPIN.Text.Trim
                .document.getElementsByTagName("input").item(7).click()

                System.Threading.Thread.Sleep(1000)

                bLong = False
                StartTime = Now
                Do While .busy = True
                    'There is a delay retrieving the website. Continue ?
                    ElapsedTime = Now().Subtract(StartTime)
                    If (ElapsedTime.TotalSeconds Mod 60) >= 50 Then
                        bLong = True
                        Exit Do
                    End If
                    System.Threading.Thread.Sleep(1000)
                Loop

                If bLong = True Then
                    PageName.Alert(Page, "There is a delay retrieving the website. Please try again.")
                    Return False
                End If

                If .document.getElementById("lastname") Is Nothing Then
                    'We have result
                    Return True
                Else
                    PageName.Alert(Page, "Attention: No matching records found.")
                    Return False
                End If

            End With

        End Function


Here are some classes used in implementing long-polling using HttpHandlers. I use this solution for operations that take a LONG time to finish. There are basically 6 classes (see below). Some of these classes may end-up being unneeded for YOUR purposes, but they made sense for mine. These have "mostly" been sanitized for you.

  1. Controller: Processes actions required to create a valid response (db operations etc.)
  2. Processor: Manages asynch communication with the web page (itself)
  3. IAsynchProcessor: The service processes instances that implement this interface
  4. Sevice: Processes request objects that implement IAsynchProcessor
  5. Request: The IAsynchProcessor wrapper containing your response (object)
  6. Response: Contains custom objects or fields

If you need help with the JavaScript or HTML add-in a comment below...I will write something for you.

HTTP HANDLERS:

using System;
using System.Configuration;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.Services;
using System.Web.SessionState;

namespace Concept.LongPolling.Handlers
{
    /// <summary>
    /// Summary description for Controller
    /// </summary>
    public class Controller : IHttpHandler, IReadOnlySessionState
    {
        #region CONSTRUCTORS
        #endregion

        #region PROPERTIES

        /// <summary>Gets a Boolean value indicating that another request can use the current instance of the DefaultHttpHandler class.</summary>
        /// <remarks>Returning true makes the same AsyncHttpHandler object be used for all requests.</remarks>
        /// <remarks>Returning false here makes ASP.Net create object per request.</remarks>
        public bool IsReusable { get { return true; } }

        #endregion

        #region METHODS

        /// <summary>Enables synchronous processing of HTTP Web requests</summary>
        /// <param name="context">An HttpContext object that provides references to the intrinsic server objects</param>
        /// /// <remarks>This is where you would send commands to the controller that would affect processing in some manner.</remarks>
        public void ProcessRequest(HttpContext context)
        {
            throw new NotImplementedException();
        }

        /// <summary>Creates the response object which is serialized back to the client</summary>
        /// <param name="response"></param>
        public static Response CreateResponse(Response response)
        {
            try
            {
                response.Generate();
            }
            catch (System.Exception ex)
            {
                response.SessionValid = false;
            }

            return response;
        }

        #endregion
    }
}

using System;
using System.Configuration;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.Services;
using System.Web.SessionState;
using Concept.LongPolling.LongPolling;

namespace Concept.LongPolling.Handlers
{
    /// <summary>
    /// Summary description for Processor
    /// </summary>
    public class Processor : IHttpHandler, IHttpAsyncHandler, IReadOnlySessionState
    {
        #region CONSTRUCTORS
        #endregion

        #region PROPERTIES

        /// <summary>Gets a Boolean value indicating that another request can use the current instance of the DefaultHttpHandler class.</summary>
        /// <remarks>Returning true makes the same AsyncHttpHandler object be used for all requests.</remarks>
        /// <remarks>Returning false here makes ASP.Net create object per request.</remarks>
        public bool IsReusable { get { return false; } }

        #endregion

        #region METHODS

        /// <summary>Enables synchronous processing of HTTP Web requests</summary>
        /// <param name="context">An HttpContext object that provides references to the intrinsic server objects</param>
        public void ProcessRequest(HttpContext context)
        {
            throw new NotImplementedException();
        }

        #region IHttpAsyncHandler Members

        /// <summary>Enables asynchronous processing of HTTP Web requests</summary>
        /// <param name="context">An HttpContext object that provides references to the intrinsic server objects</param>
        /// <param name="cb">The method to call when the asynchronous method call is complete. If callback is null, the delegate is not called.</param>
        /// <param name="extraData"></param>
        /// <returns>Any state data that is needed to process the request.</returns>
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            Int32 someValueYouLikeToSendInYourClass = Convert.ToInt32(context.Request["Number"]);

            Request request = new Request(cb, context);
            request.Response.Number = someValueYouLikeToSendInYourClass;

            Service.Singleton.AddRequest(request);

            return request;
        }

        /// <summary>Provides an end method for an asynchronous process.</summary>
        /// <param name="result">An object that contains information about the status of the process.</param>
        public void EndProcessRequest(IAsyncResult result)
        {
            Request request = result as Request;
            JavaScriptSerializer serializer = new JavaScriptSerializer();

            request.HttpContext.Response.ContentType = "text/json";
            request.HttpContext.Response.Write(serializer.Serialize(request.Response));
            request.HttpContext.Response.End();
        }

        #endregion

        #endregion
    }
}

SUPPORTING CLASSES:

using System;
using System.Runtime.InteropServices;

namespace Concept.LongPolling.LongPolling
{
    /// <summary>Represents the executable instance of an asynchronous operation.</summary>
    [ComVisible(true)]
    public interface IAsynchProcessor : IAsyncResult
    {
        /// <summary>
        /// Gets a value that indicates whether the operation completed sucessfully.
        /// </summary>
        /// <returns>true if the operation completed sucessfully; otherwise, false.</returns>
        bool ProcessRequest();
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading;

namespace Concept.LongPolling.LongPolling
{
    public sealed class Service
    {
        #region CONSTRUCTORS

        private Service()
        {
            requests = new List<IAsynchProcessor>();
            backgroundThread = new Thread(new ThreadStart(MainLoop));
            backgroundThread.IsBackground = true;
            backgroundThread.Start();
        }

        #endregion

        #region PROPERTIES

        private static Service singleton;
        private Thread backgroundThread;
        private List<IAsynchProcessor> requests;
        static readonly object padlock = new object();

        public static Service Singleton
        {
            get
            {
                if (_singleton == null)
                    lock (_padlock)
                    {
                        if (_singleton == null)
                            _singleton = new Service();
                    }

                return _singleton;
            }
        }

        #endregion

        #region METHODS

        private void MainLoop()
        {
            while (true)
            {
                foreach (IAsynchProcessor request in requests.ToArray())
                {
                    if (request.ProcessRequest())
                        requests.Remove(request);
                }
                Thread.Sleep(500);
            }
        }

        public void AddRequest(IAsynchProcessor request)
        {
            lock (padlock)
            {
                requests.Add(request);
            }
        }

        #endregion
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Concept.LongPolling.Business;
using System.Data;

namespace Concept.LongPolling.Handlers
{
    public class Response
    {
        #region CONSTRUCTORS

        public Response()
        {
            SessionValid = true;
            Exception = String.Empty;
        }

        #endregion

        #region PROPERTIES

        public const int TimeOffset = 120;

        public Int32 Number { get; set; }
        public bool SessionValid { get; set; }
        public String Exception { get; set; }

        #endregion

        #region METHODS

        public void Generate()
        {
            // do some desired operation
            Number += 1;
        }

        #endregion
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Concept.LongPolling.LongPolling;

namespace Concept.LongPolling.Handlers
{
    public class Request : IAsynchProcessor
    {
        #region CONSTRUCTORS

        public Request(AsyncCallback callback, HttpContext context)
        {
            asyncCallback = callback;
            httpContext = context;
            createdTime = DateTime.Now;

            Response = new Response();
        }

        #endregion

        #region PROPERTIES

        public const int TimeoutSeconds = 15;

        private AsyncCallback asyncCallback;
        private HttpContext httpContext;
        private DateTime createdTime;

        public bool TimedOut
        {
            get
            {
                return ((DateTime.Now - createdTime).TotalSeconds >= TimeoutSeconds);
            }
        }

        public Response Response { get; set; }

        #region IAsyncResult Members

        public HttpContext HttpContext
        {
            get
            {
                return httpContext;
            }
        }
        public object AsyncState { get; set; }

        System.Threading.WaitHandle IAsyncResult.AsyncWaitHandle
        {
            get { throw new NotImplementedException(); }
        }

        bool IAsyncResult.CompletedSynchronously
        {
            get { return false; }
        }

        public bool IsCompleted
        {
            get { return isCompleted; }
            set
            {
                if (!value) return;

                this.isCompleted = true;
                asyncCallback(this);
            }
        }
        bool isCompleted = false;

        #endregion

        #endregion

        #region METHODS

        public bool ProcessRequest()
        {
            this.Response = Controller.CreateResponse(this.Response);
            this.IsCompleted = true;

            return this.IsCompleted;
        }

        #endregion
    }
}


Take a look at this article, which describes how to execute a method asynchronously, and uses an event handler that fires when the asynchronous method call has completed.

http://www.csharp-examples.net/create-asynchronous-method/

Here's a rough draft of how you would apply the contents of the article in your situation. I haven't tested the code, so it might not be perfect, but it should be close.

You need to import the following namespaces:

using System.Threading;
using System.ComponentModel;
using System.Runtime.Remoting.Messaging;

And here is the rough implementation:

//boolean flag which indicates whether the async task is running
private bool crawling = false;

private delegate bool CrawlWebsiteDelegate();

private bool CrawlWebsite()
{
    //crawl the website

    return false;
}

protected void Button1_Click(object sender, EventArgs e)
{
    CrawlWebsiteDelegate worker = new CrawlWebsiteDelegate(CrawlWebsite);
    AsyncCallback completedCallback = new AsyncCallback(CrawlWebsiteCompletedCallback);

    if (!crawling)
    {
        worker.BeginInvoke(completedCallback, AsyncOperationManager.CreateOperation(null));
        crawling = true;
    }
}

private void CrawlWebsiteCompletedCallback(IAsyncResult ar)
{
    //get the original worker delegate and the AsyncOperation instance
    CrawlWebsiteDelegate worker = (CrawlWebsiteDelegate)((AsyncResult)ar).AsyncDelegate;

    //finish the asynchronous operation
    bool success = worker.EndInvoke(ar);
    crawling = false;

    if (success)
    {
        //perform sql tasks now that crawl has completed
    }
}

EDIT: Here is the code in VB.NET - not positive that all syntax is correct

Private crawling As Boolean = False    
Private Delegate Function CrawlWebsiteDelegate() As Boolean

Private Function CrawlWebsite() As Boolean
    Return False    
End Function

Protected Sub Button1_Click(sender As Object, e As EventArgs)
    Dim worker As New CrawlWebsiteDelegate(AddressOf CrawlWebsite)
    Dim completedCallback As New AsyncCallback(AddressOf CrawlWebsiteCompletedCallback) 
    If Not crawling Then
        worker.BeginInvoke(completedCallback, AsyncOperationManager.CreateOperation(Nothing))
        crawling = True
    End If  
End Sub

Private Sub CrawlWebsiteCompletedCallback(ar As IAsyncResult)
    Dim worker As CrawlWebsiteDelegate = DirectCast(DirectCast(ar, AsyncResult).AsyncDelegate, CrawlWebsiteDelegate)
    Dim success As Boolean = worker.EndInvoke(ar)
    crawling = False        
    If success Then
        DoSomeSqlTasks()
    End If
End Sub
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜