Update UI ASP.NET Control - Asynchronous (CallBack Approach) - Calling WebService Methods - asp.net

Here is the sample code for WebService written in ASP.NET 1.1 using VB.NET:
<System.Web.Services.WebService(Namespace := "http://tempuri.org/WebService_Simple/Service1")> _
Public Class Service1
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function Add(ByVal A As Integer, ByVal B As Integer) As Integer
System.Threading.Thread.Sleep(2000)
Return A + B
End Function
End Class
Here is the Client code:
Public Class WebForm1
Inherits System.Web.UI.Page
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim proxy As New Service1
Dim ac As New AsyncCallback(AddressOf MyCallback)
Dim ar As IAsyncResult = proxy.BeginAdd(10, 20, ac, proxy)
System.Threading.Thread.Sleep(1000)
End Sub
Public Sub MyCallback(ByVal ar As IAsyncResult)
Dim proxy As Service1 = CType(ar.AsyncState, Service1)
Dim result As Integer = proxy.EndAdd(ar)
Label1.Text = "Result = " & result.ToString()
End Sub
End Class
I am using Visual Studio.NET 2003 (ASP.NET 1.1 / VB.NET). I am getting the right values into "result" variable. But it is NOT updating the UI element (Label1). I know the reason. Because UI - MAIN - thread is different than the one which is using CALLBACK - WORKER - thread. Can you provide me sample code so that it will update the UI (Label1) control using VB.NET in Visual Studio.NET 2003 ?
Thanks

This is the answer. It is negative but it is answer. You can't and shouldn't do this in ASP.NET Web Forms because Page cycle moves through well known set of steps. There shouldn't be any async/multi-threaded programming done in page cycle methods. and you definitely shouldn't make ASP.net thread sleeping.
Your Button1_Click is part of the cycle and when it executes, ASP.net framework already executes something else. And whatever you call asynchronously is just left behind. The code executes but values never affect anything.
If you trying to achieve asynchronous behavior in ASP.net web forms, you need to include some client-side devices that will call your web service. I am not even sure now that the old framework you use has something like update panel or there is AJAX toolkit for it. Bu that is how you need to achieve it without page reloading - you use jQuery or something else to call your web service. What you tried to do in your example is a dead end.
And seriously, start using new frameworks. At least 3.5.

Related

Simple HttpResponse in ASPX VB

We have an old Asp.net 2.0 web service where I need to put in a simple HTTP response. In the below code, the function "APIValidation()" returns an int, 200 or 404. All I need to do is have it send an HttpResponse so my node web app can read the statuscode (and then do what it needs to do).
I have no idea how to do this (I'm a noob with ASP), the tutorials I find are too elaborate, it seems this could be solved in a few lines of code, I just don't know which.
You can see it in action here:
200 : http://registration.imprintplus.com/imprinttest/GlobalSrvSN.aspx?sn=29820C0792024CDC8D590BF14AF42490
404: http://registration.imprintplus.com/imprinttest/GlobalSrvSN.aspx?sn=invalid
The other option is for Node to be able to extract the 200 or 404 out of what the ASP service gives me. Either or works for me.
Option Explicit Off
Option Strict Off
Imports ActivationServer
Partial Class GlobalSrvSN
Inherits System.Web.UI.Page
Public Function APIValidation(ByVal sn As String, ByVal databaseSource As String) As String
Dim act As New LogicProtect_ActivationServer(databaseSource)
Return act.APIValidation("user", "user#company.com", sn)
End Function
End Class
thanks a million!
Unsure how you're calling that function so will assume a few things if that's the only code you have.
If you're calling it from the .aspx file then this would be an example:
<%# Page Language="vb" ....." %>
<%
Dim foo = APIValidation(Request("sn"), "other string")
Response.StatusCode = CInt(foo)
%>
If from "code behind" ([page].aspx.vb):
Option Explicit Off
Option Strict Off
Imports ActivationServer
Partial Class GlobalSrvSN
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim foo = APIValidation(Request("sn"), "other string")
Response.StatusCode = CInt(foo)
End Sub
Public Function APIValidation(ByVal sn As String, ByVal databaseSource As String) As String
Dim act As New LogicProtect_ActivationServer(databaseSource)
Return act.APIValidation("user", "user#company.com", sn)
End Function
End Class
Notes: Above is a very trivial answer to keep things simple. But:
above is really a "Web Forms Page" (not technically a "web service") which would be asmx (2.0)
Skipped any input validation (queryString), error checking/handling.
Response object is how you'd control HTTP Responses (headers, etc.)
Hth

Why am I getting an weird error on my asp.net webpage?

I am currently developing a asp.net webpage and a WCF publish subscribe service. The WCF service has been done up the subscriber is a winform app which is also done up. I am now trying to get the asp.net webpage to connect to my publish service for my WCF. However there is an weird error that I am getting. I have added the app.config and the generatedProxy.cs.vb to my asp.net project.
This is the code for my class
Public Class json
Implements IPostingContractCallback
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Response.ContentType = "application/json"
If Request.QueryString("action") = "postAlert" Then
Dim site As InstanceContext = New InstanceContext(New json())
Dim client As PostingContractClient = New PostingContractClient(site)
client.PublishPost("testing")
client.Close()
End If
End Sub
Public Sub PostReceived(ByVal postSampleData As String)
Console.WriteLine("PostChange(item {0})", postSampleData)
End Sub
the sub PostReceived is the callback method for my WCF service. It practically is meant to be do nothing as this is the Publisher, but I still have to implement it due to the WCF standards. The error that I am getting is
Class 'json' must implement 'Sub PostReceived(postSampleData As String)' for interface 'IPostingContractCallback'
How come i am getting the error when i have already implemented the sub as stated above?
Method signature must be: (Take a look at VB.NET Interfaces)
Public Sub PostReceived(ByVal postSampleData As String) Implements IPostingContractCallback.PostReceived
Console.WriteLine("PostChange(item {0})", postSampleData)
End Sub

How to print in VB?

I have a web application build using classic ASP and VB. How do I print a document from within the back end VB code?
Protected Sub btnPrint_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPrint.Click
End Sub
What i am trying to do is get user to click on button a letter is generated and sent to printer?
You could use the window.print javascript function which will open the print dialogon the client browser allowing him to choose the printer and print the page:
Protected Sub btnPrint_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPrint.Click
ClientScript.RegisterStartupScript([GetType](), "print", "window.print();", true)
End Sub
As a side note, what you have is not a classic ASP application with VB, you have a classic ASP.NET WebForms application using VB.NET as a code behind.
UPDATE:
As requested in the comments section here's how you could write a generic handler which will dynamically generate the HTML you would like to print:
Imports System.Web
Imports System.Web.Services
Public Class Print
Implements System.Web.IHttpHandler
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/html"
context.Response.Write("<html><body onload=""window.print();""><table><tr><td>value1</td><td>value1</td></tr></table></body></html>")
End Sub
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
Now simply navigate to /Print.ashx.
you could look into some reports frameworks like CrystalReports (used to come with VS but you have to download it from SAP nowadays.
Here is a nice tutorial for the report-engine that comes packed into Visual Studio (I have to admit I don't have much experience with this but it looks fine to me): Creating an ASP.NET Report

problem using winforms WebBrowser in asp.net

i am using the WebBrowser control in asp.net page. here is the simple code:
Public Class _Default
Inherits System.Web.UI.Page
Private WithEvents browser As WebBrowser
Dim th As New Threading.Thread(AddressOf ThreadStart)
Sub ThreadStart()
browser = New WebBrowser
AddHandler browser.DocumentCompleted, AddressOf browser_DocumentCompleted
browser.Navigate("http://www.someurl.com/")
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
th.SetApartmentState(Threading.ApartmentState.STA)
th.Start()
th.Join()
End Sub
Private Sub browser_DocumentCompleted(ByVal sender As Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
If browser.Document IsNot Nothing Then
Dim textbox As HtmlElement = browser.Document.GetElementById("txt1")
textbox.InnerText = "some text"
Dim button As HtmlElement = browser.Document.GetElementById("btn1")
button.InvokeMember("click")
End If
End Sub
End Class
the problem is that the webbrowser's DocumentCompleted event is not being handled. It looks like the page request finishes before anything else could happen.
what's the solution to this problem?
I really recommend reading this article(He won a price for it..)
Using the WebBrowser Control in ASP.NET
http://www.codeproject.com/KB/aspnet/WebBrowser.aspx
His solution is to create 3 threads for it to work..
I'm not sure but I have some concerns about the way you wrote your code.
You are creating and initializing your thread as soon as your class instance is created. This is before the form has been loaded.
I can't say for sure this couldn't work but I would definitely recommend creating the thread in your Load event handler, just before you use it.
I wrote some similar code in C# to generate a website thumbnail. Although that code does not use the DocumentCompleted event, I played with that event when I wrote it and it seemed to work okay. You can compare my code to yours.
Also, I should mention I have one hosting account where the code doesn't work. It seems to simply die when I call Thread.Join. However, it doesn't appear that's the issue you're running into.

"Re-Raising" Custom Events in .NET (ASP.NET in this case)

I'm working on an ASP.NET page, using VB.NET and I have this hierarchy:
Page A
- Web User Control 1
- Web User Control A
- Web User Control B
- Web User Control C
I need to raise an event from Web User Control B that Page A will receive (the event flow will be Web User Control B -> Web User Control 1 -> Page A).
My only approach so far has been this:
1) Add a custom event declaration to both Web User Control B and Web User Control 1 and simply RaiseEvent twice until it gets to Page A (this seems ugly and I don't particularly like it).
My other idea was to create a custom Event class that inhertis from some magical base Event class and create an instance of it in both Web User Control B and Web User Control 1, but that is proving fruitless because I can't find any event base classes (maybe b/c they're aren't any, since it appears to be a keyword, not a class name).
Any help would be appreciated! Thanks and happy coding!
You can use the BubbleEvent concept to do this. A BubbleEvent goes up the control hierarchy until someone handles it. The GridView and Repeater controls do this with their Row/ItemCommand events.
You could implement it into WebUserControl1, turning it into a standard event for the page (like the GridView does):
Class UserControl1 ' Parent
Protected Override Function OnBubbleEvent(sender as Object, e as EventArgs) as Boolean
Dim c as CommandEventArgs = TryCast(e, CommandEventArgs)
If c IsNot Nothing Then
RaiseEvent ItemEvent(sender, c)
Return True ' Cancel the bubbling, so it doesn't go up any further in the hierarchy
End If
Return False ' Couldn't handle, so let it bubble
End Function
Public Event ItemEvent as EventHandler(Of CommandEventArgs)
End Class
Class UserControlB ' Child
Protected Sub OnClicked(e as EventArgs)
' Raise a direct event for any handlers attached directly
RaiseEvent Clicked(Me, e)
' And raise a bubble event for parent control
RaiseBubbleEvent(Me, New CommandEventArgs("Clicked", Nothing))
End Sub
Protected Sub OnMoved(e as EventArgs)
' Raise a direct event for any handlers attached directly
RaiseEvent Moved(Me, e)
' And raise a bubble event for parent control
RaiseBubbleEvent(Me, New CommandEventArgs("Moved", Nothing))
End Sub
End Class
Class PageA
Sub UserControl1_ItemEvent(sender as Object, e as CommandEventArgs) Handles UserControl1.ItemEvent
Response.Write(sender.GetType().Name & " was " & e.CommandName)
End Sub
End Class
Or, do it directly in the page. UserControlB (Child) is the same as above, and UserControl1 (Parent) doesn't need to do anything special - OnBubbleEvent defaults to returning False, so the event bubbles up:
Class PageA
Protected Override Function OnBubbleEvent(sender as Object, e as EventArgs) as Boolean
If sender Is UserControlB Then
Dim c as CommandEventArgs = TryCast(e, CommandEventArgs)
If c IsNot Nothing Then
Response.Write(sender.GetType().Name & " was " & c.CommandName)
Else
Response.Write(sender.GetType().Name & " raised an event, with " & e.GetType().Name & " args)
End If
Return True ' Cancel the bubbling, so it doesn't go up any further in the hierarchy
End If
Return False ' Not handled
End Function
End Class
If your initial event is from a server control (like a Button.Click), then it will have been coded to already raise the bubble event - so UserControlB (Child) doesn't need to do anything to get that to the parent either. You just need to call RaiseBubbleEvent for any of your custom events, or if you want to transform the EventArgs in some way.
The real question here is is the actual action in Web UserControl B something that should notify both, OR, is WebUserControl1 responsible for some processing BEFORE notifying the page.
If each step of the chain has a specific action, your method of raising two events is proper. If it is in a manner where the event just needs to notify everyone you will want to look at different subscription methods to communicate.
Create a Assembly (or Namespace) that is referenced by everything.
Create a interface with the methods you need.
Create a class that manages objects that implemented the interface.
Have Page A implement the interface
Have Page A register itself with the manager class done in step #3
Now Web UserControl B can raise the event by retrieving the page from the manager and calling the method on the interface that raises the event you need.
You avoid tightly coupling the page to the webcontrol because you are using a interface.
Likely you will find that you will have a multiple interface for different areas of your project. For example in my CAM project I have a interface for the Setup Parameters UI, the Shape Entry UI, and the Cut Entry UI. On our website we have different product categories that uses different interfaces. (Software, Machinery, Services, etc).
You can create a public method in Page A which gets called from Web User Control B instead of raising an event up the entire control tree.
This would not be my first choice since this will cause tight coupling between those classes but I hope it solves your problem.
Sample Page:
Public Partial Class TestPage
Inherits Page
Public Sub PerformAction()
'Whatever needs to be done on Page A
End Sub
End Class
Sample User Control:
Public Partial Class TestControl
Inherits UserControl
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'This will call the Page, obviously this will only
'work when the control is on TestPage
CType(Page, TestPage).PerformAction()
End Sub
End Class

Resources