Capturing the output of a ASP template for unittesting - asp-classic

I'm trying to find a way to capture the response of ASP templates for testing purposes. After reading this post i was hoping that the following code would provide a solution:
class cMockResponse
public data
public sub write( value)
if isempty(data) then data = ""
data = data & value
end sub
end class
class cView
public response
private sub class_initialize()
set response = new cMockResponse
end sub
public sub render()
' expected that the following would be compiled to response.write "hello world"
%> hello world <%
end sub
end class
set view = new cView
call view.render()
response.write "the mock respone was:" & view.response.data
Given the blog post i hoped that
%> hello world <%
would be simply translated to
response.write "hello world"
Since response references the mock object I hoped that this solution would do the trick, but clearly it doesn't. The output of the above code is unsurprisingly:
hello world the mock response was:
Are there other methods to capture the output of ASP templates programatically without resorting to internal xmlhttp requests?

As far as I am aware of it is not possible to capture the output.
If you require unit testing for classic ASP you might have a look at ajaxed

Related

Access winform variable from browsercontrol

I have an application in ASP.Net Ajax. I want to open it via a browsercontrol from a winform, and I wish to access a variable (username) that the user used to log in to the webform with. On load I would like to read that username and perform the rest of my webpage code on that browsercontrol using that username.
My ASP.Net Ajax has been published to a internal web server and the browsercontrol loads that IP address.
Is there any way to achieve this at all?
EDIT:
I have discovered the javascript extension: window.external
And I can call a C# procedure from the webpage using javascript with it, which is a start, but I need to retrieve a varaible from c# - this is where the problem comes in. I have tried the
var name = function window.external.GetGlobalVariable(MyGlobalProcedure, "Cannot Get Value");
But javascript error says the method cannot be applied to the object.
Your answer should be as follows:
Public Class Form1
Dim GlobalVar As String = "Your Name"
Dim YourBrowser As New WebBrowser
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
YourBrowser.Url = New Uri("Your URL address")
AddHandler YourBrowser.DocumentCompleted, AddressOf PageLoadComplete
End Sub
'The invokescript will only work once the HTML has finished loading itself into your WebBrowser
Sub PageLoadComplete()
'Must declare the string inside an array as the invokescript only allows an object to be sent
Dim VarToSend As String() = {GlobalVar}
YourBrowser.Document.InvokeScript("yourJavascriptfunction", VarToSend)
End Sub
The javascript section should look as follows:
<script type="text/javascript" language="javascript">
function userNameSet(name) {
$(document).ready(function() {
//variable now exists inside your WebBrowser client and can be used accordingly now
alert(name);
});
}
</script>
References for answer: http://www.dotnetcurry.com/showarticle.aspx?ID=194
"Store that name in a session variable and access the session in your ajax call"
In your ASP.Net application create a hidden field (or if it's somewhere on the UI in some control that works also). Put the username or whatever information you want to share into that field.
From your WinForms program you can request that field through the WebBrowser control like this:
MessageBox.Show(WebBrowser1.Document.GetElementById("txtUsername").GetAttribute("value"))
The above assumes you have some HTML element called txtUsername with the value attribute set.

How to show alert from separate code module in asp.net

How do you show an alert from a separate code moduel in asp.net, not the codebehind of a page, thats an easy one.
This is one way to do it from the code behind of a page.
ScriptManager.RegisterStartupScript(Page, Me.GetType, "alert('Hello')", True)
How can i achieve this from a separate code module though, i am not sure. it needs a control and control type for the first to parameteres respectively. So the code above will error out on the first 2 params. Does anyone have a solution?
You need to pass the Page object of the current request to this extern module. Then you can use it in the RegisterStartupScript function. For example:
Some extern class:
Public Class MyClass
Public Shared Sub DoSomething(Page As Page)
' do something
ScriptManager.RegisterStartupScript(Page, Page.GetType, "alert('Hello');", True)
End Sub
End Class
In theaspx page or CodeBehind:
' ...
MyClass.DoSomething(Page)
' ...

Instantiating a class within WCF

I'm writing a WCF WebMethod to upload files to, of which I taken snippets from around the web. The WCF interface looks like this:
<ServiceContract()>
Public Interface ITransferService
<OperationContract()>
Sub UploadFile(ByVal request As RemoteFileInfo)
End Interface
<MessageContract()>
Public Class RemoteFileInfo
Implements IDisposable
<MessageHeader(MustUnderstand:=True)>
Public FileName As String
<MessageHeader(MustUnderstand:=True)>
Public Length As Long
<MessageBodyMember(Order:=1)>
Public FileByteStream As System.IO.Stream
Public Sub Dispose() Implements IDisposable.Dispose
If FileByteStream IsNot Nothing Then
FileByteStream.Close()
FileByteStream = Nothing
End If
End Sub
End Class
Within ASP.NET, when the web method is consumed, for some reason it only works when the interface is used as part of the instantiation of RemoteFileInfo:
Protected Sub btn_Click(sender As Object, e As EventArgs) Handles btn.Click
If fu.HasFile Then
Dim fi As New System.IO.FileInfo(fu.PostedFile.FileName)
' this is the line in question --------------
Dim cu As ServiceReference1.ITransferService = New ServiceReference1.TransferServiceClient()
' -------------------------------------------
Dim uri As New ServiceReference1.RemoteFileInfo()
Using stream As New System.IO.FileStream(fu.PostedFile.FileName, IO.FileMode.Open, IO.FileAccess.Read)
uri.FileName = fu.FileName
uri.Length = fi.Length
uri.FileByteStream = stream
cu.UploadFile(uri)
End Using
End If
End Sub
Can anyone advise why it is not possible to create an instance of TransferService using the following approach:
Dim cu As New ServiceReference1.TransferServiceClient()
If I try the above, it breaks this line:
cu.UploadFile(uri)
...and UploadFile must be called with three parameters (FileName, Length, FileByteStream) even there is no method that uses this signature.
Why is the Interface required when creating an instance of this class please?
When you create the proxy for your service with the "Add Service Reference" dialog, by default the proxy creation code will "unwrap" message contracts, like the one you have. If you want the message contract to appear as you defined on the server side on your proxy, you need to select the "Advanced" tab, and check the "Always generate message contracts" option. With that you'll get the message contract in your client as well.
The issue is that when a MessageContract is encountered as a parameter, the WCF client generation assumes by default that you want to implement a messaging-style interface, and provides the discrete properties from the message contract as part of the client-side interface.
The Using Messaging Contracts article in MSDN contains a very detailed description of what can be done with a messaging contract and I suspect that Microsoft chose this default behavior because of some of the "games" that you can play with the messages.
However, if you examine the code generated for your UploadFile on the client side, there are some interesting tidbits that help to explain what is going on.
The first is the comments for the UploadFile method in the interface:
'CODEGEN: Generating message contract since the operation UploadFile is neither RPC nor document wrapped.
...
Function UploadFile(ByVal request As ServiceReference1.RemoteFileInfo) As ServiceReference1.UploadFileResponse
This implies that the contract would have been generated differently if the message contract had a different implementation.
The second is that you will see that there is nothing special about the code that is used to actually make the service call:
Public Sub UploadFile(ByVal FileName As String, ByVal Length As Long, ByVal FileByteStream As System.IO.Stream)
Dim inValue As ServiceReference1.RemoteFileInfo = New ServiceReference1.RemoteFileInfo()
inValue.FileName = FileName
inValue.Length = Length
inValue.FileByteStream = FileByteStream
Dim retVal As ServiceReference1.UploadFileResponse = CType(Me,ServiceReference1.ITransferService).UploadFile(inValue)
End Sub
So in this case, your code is doing exactly what the generated code does. However, if the MessageContract were more complex, I suspect that this would no longer be the case.
So, for your question:
Can anyone advise why it is not possible to create an instance of
TransferService using the following approach...
There is no reason not to take this approach as long as you verify that the implementation of the method call is functionality equivalent to your code.
There are a couple of options for changing the default generation of the method in the client:
1) Remove the MessageContract attribute from the RemoteFileInfo class.
2) Although it seems to be counter-intuitive, you can check the Always generate message contracts checkbox in the Configure Service Reference Dialog Box.

Response.Redirect to Class that inherits from UI.Page?

everyone, thank for your time.
Well this my problem (well it's not a probleam at all), it is possible to have a class that inherits from ui.page and then instance an object of that class and do a redirect to it ?
Something like this:
Public sub myMethod()
Dim myPage as new myClassThatInheritsFromUIPage()
Response.redirect(myPage) 'Here is one of my "no-idea" line
end sub
I do this in my webForm (and that what I want to do in a class that inherits from ui.page):
Response.BufferOutput = True
Response.ClearContent()
Response.ClearHeaders()
ostream=crReportDocument.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat)
Response.AppendHeader("Cache-Control", "force-download")
Response.AppendHeader("Content-disposition","attachment;filename=ReportAsPDF.pdf")
Response.ContentType = "application/pdf"
Response.BinaryWrite(ostream.ToArray())
Response.Flush()
HttpContext.Current.ApplicationInstance.CompleteRequest()
What I want to do is perfectly possible with a normal WebForm, but my webForm doesn't render nothing at all (at least as (x)html so, that's because I would like to know if what I'm asking is possible to achieve.
Thank you everyone.
Well at the end I just add "HttpContext.Current." to all the lines that include a "response" attribute, so now I have just a class that NOT inherits from "UI.Page" and just call the method that clear the buffer (a custom method), add the headers (to force the download,set the mime type and filename) and flush the response by itself and get the effect/use I want it.
In order to access to the Session vars just add "HttpContext.Current." and it works, I don't know how secure or if is a good way,but appears to work well.
So the code now looks something like this:
Imports CrystalDecisions.CrystalReports.Engine
Imports CrystalDecisions.Shared
Imports CrystalDecisions.ReportSource
Namespace foo
Public Class requestReport
'just to instance the object'
Public Sub New()
End Sub
Public Sub downloadReport()
'do all the stuff to connect and load the report'
HttpContext.Current.Response.BufferOutput = True
HttpContext.Current.Response.ClearContent()
HttpContext.Current.Response.ClearHeaders()
ostream=crReportDocument.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat)
HttpContext.Current.Response.AppendHeader("Cache-Control", "force-download")
HttpContext.Current.Response.AppendHeader("Content-disposition","attachment;filename=ReportAsPDF.pdf")
HttpContext.Current.Response.ContentType = "application/pdf"
HttpContext.Current.Response.BinaryWrite(ostream.ToArray())
HttpContext.Current.Response.Flush()
HttpContext.Current.ApplicationInstance.CompleteRequest()
End Sub
End Class
End Namespace
And from a command for example do this:
dim myReport as new foo.requestReport()
myReport.downloadReport()
Of course now you can add more attributes or method if you need it.
So now I don't even don't use Response.redirect() or inherits from "UI.Page", just a class that "change" the "current response" and "flush" the content created on fly with the crystal report, I think I was kind of totally lost but your answers really help me, especially what Tejs says, what is almost the same or the same what I just did. Thank you.
UPDATE:
By the way, I just realize that the ReportDocument class has this method: ExportToHttpResponse that let us flush the Crystal Report to the browser as PDF/XSL etc forcing (or not) the download of the file.
No, as there is no current overload that accepts a UI.Page instance. However, you could call the Render method on your new page and write directly to the response stream. AKA
Clear the Response Buffer.
Render your page instance to the response buffer.
Invoke Response.End() to flush the request and send it to the client.
If your new page doesnt actually do anything, you can additional just send no content back with the response.
You can use Server.Transfer and pass in the instance of the page object that you want to tranfer to.
Here is the documentation: HttpServerUtility.Transfer
Try just doing this instead:
HttpContext.Current.Response.Redirect("...");
HttpRequest Request = HttpContext.Current.Request;
HttpResponse Response = HttpContext.Current.Response;
And after that you can redirect any page.

Can't set Response object in ASP Classic

This line:
set Response = nothing
Fails with the error
"Microsoft VBScript runtime error '800a01b6'
Object doesn't support this property or method: 'Response' "
Now, I can think of any number of reasons why the engine might not want to let me do such a seemingly silly thing, but I'm not sure how a missing method could be stopping me.
EDIT: Here is an example of what I'd like to do with this.
class ResponseBufferEphemeron
private real_response_
private buffer_
private sub class_initialize
set real_response_ = Response
end sub
private sub class_terminate
set Response = real_response_
end sub
public function init (buf)
set buffer_ = buf
set init = me
end function
public function write (str)
buffer_.add str
end function
end class
function output_to (buf)
set output_to = (new ResponseBufferEphemeron).init(buf)
end function
dim buf: set buf = Str("Block output: ") ' My string class '
with output_to(buf)
Response.Write "Hello, World!"
end with
Response.Write buf ' => Block output: Hello, World! '
You can't set the Response to nothing.
The ASP Response object is used to send output to the user from the server.
What are you trying to do? If you're trying to end the Response to the user, use
Response.End
Well, I found the answer here: http://blogs.msdn.com/b/ericlippert/archive/2003/10/20/53248.aspx
So we special-cased VBScript so that it detects when it is compiling code that contains a call to Response.Write and there is a named item in the global namespace called Response that implements IResponse::Write. We generate an efficient early-bound call for this situation only.

Resources