Silverlight HttpWebRequest.Create hangs inside async block - silverlight

I am trying to prototype a Rpc Call to a JBOSS webserver from Silverlight (4). I have written the code and it is working in a console application - so I know that Jboss is responding to the web request. Porting it to silverlight 4, is causing issues:
let uri = new Uri(queryUrl)
// this is the line that hangs
let request : HttpWebRequest = downcast WebRequest.Create(uri)
request.Method <- httpMethod;
request.ContentType <- contentType
It may be a sandbox issue, as my silverlight is being served off of my file system and the Uri is a reference to the localhost - though I am not even getting an exception. Thoughts?
Thx
UPDATE 1
I created a new project and ported my code over and now it is working; something must be unstable w/ regard to the F# Silverlight integration still. Still would appreciate thoughts on debugging the "hanging" web create in the old model...
UPDATE 2
let uri = Uri("http://localhost./portal/main?isSecure=IbongAdarnaNiFranciscoBalagtas")
// this WebRequest.Create works fine
let req : HttpWebRequest = downcast WebRequest.Create(uri)
let Login = async {
let uri = new Uri("http://localhost/portal/main?isSecure=IbongAdarnaNiFranciscoBalagtas")
// code hangs on this WebRequest.Create
let request : HttpWebRequest = downcast WebRequest.Create(uri)
return request
}
Login |> Async.RunSynchronously
I must be missing something; the Async block works fine in the console app - is it not allowed in the Silverlight App?

(Thanks for sending this to fsbugs, to force us to take a hard look.)
The problem is Async.RunSynchronously. When called on the UI thread, this blocks the UI thread. And it turns out that WebRequest.Create() on Silverlight dispatches to the UI thread. So it is a deadlock.
In general, try to avoid Async.RunSynchronously on Silverlight (or on any UI thread). You can use Async.StartImmediate in this example. Alternatively, I think you can call RunSynchronously from any background thread without issues. (I have not tried enough end-to-end Silverlight scenarios myself to offer more advice as yet. You might check out
Game programming in F# (with Silverlight and WPF)
F# and Silverlight
F# async on the client side
for a few short examples.)
(In retrospect, the F# design team thinks that we maybe should not have included Async.RunSynchronously in FSharp.Core for Silverlight; the method potentially violates the spirit of the platform (no blocking calls). It's possible we'll deprecate that method in future Silverlight releases. On the other hand, it still does have valid uses for CPU-intensive parallelism on Silverlight, e.g. running a bunch on (non-IO) code in parallel on background threads.)

Seems like a similar issue here - though no reference to silverlight (in fact it is a "windows service class"):
http://social.msdn.microsoft.com/Forums/en-US/netfxnetcom/thread/10854fc4-2149-41e2-b315-c533586bb65d

I had similar problem. I was making a Silverlight MVVM ViewModel to bind data from web.
Don Syme commented himself:
I’m not a data-binding expert, but I
believe you can’t “hide” the asyncness
of a view model like this for WPF and
Silverlight. I think you would need to
expose Task, Async or an
observable collection. AFAIK the only
way to get Silverlight and WPF to bind
asynchronously to a property is if it
is an observable collection.
Anyway, I installed F# Power Pack to get AsyncReadToEnd.
It didn't solve the case... I added domains to trusted sites but it didn't help... Then I added a MySolution.Web -asp.net-site and clientaccesspolicy.xml. I don't know if those had any effect.
Now, with Async.StartImmediate I got web service call working:
let mutable callresult = ""
//let event = new Event<string>()
//let eventvalue = event.Publish
let internal fetch (url : Uri) trigger =
let req = WebRequest.CreateHttp url
//req.CookieContainer <- new CookieContainer()
let asynccall =
async{
try
let! res = req.AsyncGetResponse()
use stream = res.GetResponseStream()
use reader = new StreamReader(stream)
let! txt = reader.AsyncReadToEnd()
//event.Trigger(txt)
callresult <- txt //I had some processing here...
trigger "" |> ignore
with
| :? System.Exception as ex ->
failwith(ex.ToString()) //just for debug
}
asynccall |> Async.StartImmediate
Now I will need my ViewModel to listen the mutable callresult.
In your case you need also a crossdomain.xml to the server.
The trigger is needed to use the UI-thread:
let trigger _ =
let update _ = x.myViewModelProperty <- callresult
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(new Action(update)) |> ignore
fetch serviceUrl trigger

I think you are hitting the maximum http connections restriction: see Aynchronous web server calls in Silverlight and maximum HTTP connections and http://weblogs.asp.net/mschwarz/archive/2008/07/21/internet-explorer-8-and-maximum-concurrent-connections.aspx

Related

WPF Application freezes for 20 seconds

I have a WPF (MVVM with Prism) application
There are quite a lot of factors that can affect this problem, but I will try to boil it down.
Hopefully I can at least get some tips how to trouble shoot this.
I have a user control containing a datagrid and a typical Search-button. The grid is initially empty and on SearchCommand. The user control uses a class "AccountServiceGateway" (_accountSG below) to make a request to the server, and then fills datasource of the grid with the result. Pretty standard.
VM: Binding command to handler in ctor
...
SearchCommand = new DelegateCommand(async () => await SearchOnServer(new AccountFilterDTO()));
VM, Button handler implementation
private async Task<bool> SearchOnServer(AccountFilterDTO filter)
{
var searchAccountResults = await _accountSG.SearchAccounts(filter);
//AccountSearchResultList is an observable collection that is datasource for the grid
AccountSearchResultList = new ObservableCollection<AccountSearchResultDTO>(searchAccountResults);
}
// Account Service gateway, making a web request
protected async Task<T> GetFromUrl<T>(string urlPart)
{
...
var response = await _httpClient.GetAsync(url);
resStr = await response.Content.ReadAsStringAsync();
//convert to T and return
}
EDIT
When I replace the implementation of GetFromUrl() with
await Task.Delay(5000)
return [hardcoded list of T]
everything works ok (although the hardcoded list is only 5 items)
END EDIT
Now to my problem. Getting an answer from the server taks about 1-2secs, as expected. I can follow the code until my datasource is filled. But then the GUI freezes for roughly (10-)20 seconds before anything is displayed, then efter the freeze, everything is as expected.
Other things to notice is that user control is in a Prism-region, within a Telerik RadTabbedWindow, so if this looks ok ith might be something else.
So my main question is, why does it hang for 20 seconds, I suspect there is some threading problem, but if it where a deadlock, wouldnt it hang forever? Any way to trouble shoot this?
Has the view changed in some way so that list virtualisation has been effectively turned off?
eg. Parent ScrollerViewer been added

Same functionality as HTTPClient in Codename one

I was wondering how I can achieve something like an HTTPClient.
I tried WebBrowser class but it seems that the execution continues even though the URL specified has not yet loaded.
public void testWebBrowser(){
final WebBrowser b = new WebBrowser(){
#Override
public void onLoad(String url) {
BrowserComponent c = (BrowserComponent)this.getInternal();
JavascriptContext ctx = new JavascriptContext(c);
// I want this Javascript context here
}
};
// just a test URL
b.setURL("http://youtube.com");
// Suppose to get the Javascript context here though it executes without waiting for the whole page to load
}
How can I get the JS Context from within a WebBrowser context? Like a synchronous execution
WebBrowser browser = new WebBrowser();
browser.setURL("someURL");
// wait execution till the whole page in "someURL" loads till it executes the next line
BrowserComponent c = (BrowserComponent)browser.getInternal();
JavascriptContext ctx = new JavascriptContext(c);
If I understand correctly you are trying to create a scraping solution?
That's probably not the ideal approach since this will actually create a web browser which you then need to automate with JavaScript. I would suggest you create a webservice that encapsulates the HttpClient functionality and drive it with ConnectionRequest. This way when the web site changes you can just fix your server in a way seamless to your installed base.

How to display XML-RPC.Net Server instance data in the UI?

We've trying recently to use XML-RPC.Net library on our project.
Both server(.Net Remoting) and client have been made according to the instructions we've found on http://xml-rpc.net/.
The connection has been made, we obtain data from the server and so on.
As the title states, now, we'd like to know how to make our XML-RPC server instance, which is created after the first client call, be able to give feedback to a WPF UI.
What we'd like to accomplish is to register an event on a server property so the call could arrive to the UI thread.
We are open to any suggestions in this regard.
Here is the code that registers the channel on server side:
IDictionary props = new Hashtable();
props["name"] = "SubsetHttpChannel";
props["port"] = 5678;
channel = new System.Runtime.Remoting.Channels.Http.HttpChannel(
props,
null,
new XmlRpcServerFormatterSinkProvider()
);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType( typeof(SubsetServer), "subsetserver.rem", WellKnownObjectMode.Singleton);
This is the code that shows how we'd like to set the property after Server instance is created on the UI:
Server = new SubsetServer();
Server.Machine.OnChangeState += delegate(State actual, State next, Event pEvent)
{
uiWindowInstance.PostMessage(string.Format("Subset Server: {0} -> {1}", actual.Name, next.Name));
};
Technologies used: VS2012, WPF 4.5 and XML-RPC.NET 2.5.0
Thanks in Advance
Thanks to anyone that took the time to read it and try to answer.
I found a solution that fits me for the moment. I'd like to share it with you in the hope someone could give any hints wheter this is a solution that may generate problems in the future.
After analyzing, I found out that both server instances run in the same process. So I've created a Singleton as a property inside my Server.
I've put whatever I need inside the Singleton, so for the delegate I'd like to use in my question, the code now is:
Server = new SubsetServer();
Server.**singleton**.Machine.OnChangeState += delegate(State actual, State next, Event pEvent)
{
uiWindowInstance.PostMessage(string.Format("Subset Server: {0} -> {1}", actual.Name, next.Name));
};
Hope this helps anyone else.
Please comment if you find any flaws.

How to register own protocol using the WebBrowser control?

In a WP7 Silverlight application with a WebBrowser control I want to use an own protocol like "myttp://" to deliver some local content. I can't use Navigate() to an IsolatedStrorage because some content will by created on demand. For the same reason NavigateToString() is also not usable for me.
I tried to register a WebRequestCreator descend for my MYTP protocol
myCreator = new MyRequestCreator();
WebRequest.RegisterPrefix("mytp://", myCreator);
but it isn't called from the browser control if I navigate to "mytp://test.html".
If I create a WebRequest via code
WebRequest request;
request = WebRequest.Create("mytp://test.html");`
everythings works fine.
Any suggestions what is wrong or how to do it?
The WebBrowser control will use the Windows Phone Internet Explorer Browser's HTTP stack to statisfy web requests. This HTTP stack is entirely separate from the Client HTTP stack being used by the application. Hence the browser does not see your protocol at all.
I agree with AnthonyWJones words, though I dont know, what exactly he meant by "Browser HTTP stack".
The standard Silverlight's "access to Browser's stack" (used to handle sessions etc) in form of System.Net.Browser.WebRequestCreator.BrowserHttp httprequest factory (versus the "normal/aside" System.Net.Browser.WebRequestCreator.ClientHttp factory) is actually available to the application code in WP7. It is hidden from the SDK, but available on the device and with small effort, the application can use it, for example, to have its emitted cookies in sync with the Browser's cache. For description, please see my humble other post
However, while using that factory and having all your session/cookies/userauth handling within those connections in sync with the WebBrowser, despite being very similar to the ClientHttp factory, you find (at least in 7.0 and 7.1 versions) that it is completely ignorant of any custom prefixes. Trying to open anything with this factory results in (WP7 v. Mango 7.1):
A first chance exception of type 'System.Net.ProtocolViolationException' occurred in System.Windows.dll
at System.Net.Browser.BrowserHttpWebRequest.InternalBeginGetRequestStream(AsyncCallback callback, Object state)
at System.Net.Browser.AsyncHelper.BeginOnUI(BeginMethod beginMethod, AsyncCallback callback, Object state)
at System.Net.Browser.BrowserHttpWebRequest.BeginGetRequestStream(AsyncCallback callback, Object state)
at MyApp.MyPage..ctor()
relevant code snippet of the MyPage:
public class WRC : IWebRequestCreate { public WebRequest Create(Uri uri) { return null;/*BREAKPOINT1*/ } }
WebRequest.RegisterPrefix("js://", new WRC()); // register the above handler
brwHttp = (IWebRequestCreate)typeof(System.Net.Browser.WebRequestCreator).GetProperty("BrowserHttp").GetValue(null, null);
var tmp = brwHttp.Create(new Uri("js://blah.blah.blah"));
var yyy = tmp.BeginGetResponse(callback, "wtf");
var response = tmp.EndGetResponse(yyy); /*BREAKPOINT2*/
var zzz = tmp.BeginGetRequestStream(callback, "wtf"); /*<---EXCEPTION*/
var stream = tmp.EndGetRequestStream(zzz); /*BREAKPOINT3*/
Execution results:
breakpoint1 never hit
breakpoint2 allows to see that "response" is NULL
breakpoint3 never hit due to the exception pasted above
My conclusion is, that the Silverlight Browser's stack is hardcoded to use some builtin set of prefixes, and all other prefixes are ignored/throw ProtocolViolation. My guess is, that in WP7 (7.0, 7.1) they are actually hardcoded to use http since my custom "js://" was passed to a BrowserHttpWebRequest.InternalBeginGetRequestStream as it's visible on the stacktrace :)
That confirms what Anthony had written - no way of having custom protocol handlers to work gracefully with the Silverlight's Browser Stack API.
However, I cannot agree with that the WebBrowser uses this connection factory. While is it true that the hidden factory is called BrowserHttp, and is true that it shares some per-user or per-session settings with the webbrowser, everything I try tens to indicate that the WebBrowser component uses yet completly other factory for its connections, and quite probably it is some native one. As an argument for that, I can only provide that I was able to successfully replace the original BrowserHttp factory with my simple custom implementation of it (both on the emulator and the phone), and with at least 6 webbrowsers in my current app, it wasn't used at all, not even once! (neither on the emulator, nor phone)

How to fix the WCF maxClockSkew problem in a HTTPS Silverlight application context?

Situation: Silverlight 4 app communicating with a server component through WCF, using basicHttpBinding and HTTPS.
Here is the binding used server side:
<basicHttpBinding>
<binding name="DefaultSecuredBinding" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
<readerQuotas maxDepth="50" maxArrayLength="2147483647" maxStringContentLength="2147483647" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
<transport clientCredentialType="None" proxyCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
Notice that we use TransportWithMessageCredential as security mode.
Certificate is correctly installed on IIS.
Application runs smoothly when running locally.
However, we now have external users connecting to our application.
Some of them are experiencing difficulties, and looking inside the server logs, we discovered this error:
"MessageSecurityException"
The security timestamp is stale because its expiration time ('2010-10-18T22:37:58.198Z') is in the past. Current time is '2010-10-18T22:43:18.850Z' and allowed clock skew is '00:05:00'.
We did the usual research on the topics on the web (StackoverFlow & Google... and Bing), to read more on the topic.
We contacted the users to ensure that they were time offset with our server, which was later confirmed.
This MSDN article was the start:
http://msdn.microsoft.com/en-us/library/aa738468.aspx
Which use a CustomBinding over an existing binding and sets the MaxClockSkew property on the SecurityBindingElement of the custom binding.
We implemented this solution, changing however the SymmetricSecurityBindingElement to a TransportSecurityBindingElement, since our binding for secure communication with Silverlight
is basicHttpBinding with HTTPS.
Several articles on the web (including this MSDN article listed above) show code snippets that additionally set the maxClockSkew property to a bootstrap elements taken from ProtectionTokenParameters.
I never succeeded to apply this part in our code, since TransportSecurityBindingElement doesn't seem to have any ProtectionTokenParameters.
Here is our code to wrap a binding with maxClockSkew:
protected virtual System.ServiceModel.Channels.Binding WrapClockSkew(System.ServiceModel.Channels.Binding currentBinding)
{
// Set the maximum difference in minutes
int maxDifference = 300;
// Create a custom binding based on an existing binding
CustomBinding myCustomBinding = new CustomBinding(currentBinding);
// Set the maxClockSkew
var security = myCustomBinding.Elements.Find<TransportSecurityBindingElement>();
if (security != null)
{
security.LocalClientSettings.MaxClockSkew = TimeSpan.FromMinutes(maxDifference);
security.LocalServiceSettings.MaxClockSkew = TimeSpan.FromMinutes(maxDifference);
}
return myCustomBinding;
}
The 'security.LocalClientSettings' may be useless here, since this code is for the server side.
This code didn't do the trick, we still had the same error message on server when we had more than 5 minutes difference with the server.
I still had in mind that we did not apply the bootstrap trick of the MSDN code snippet.. so we continued our web search on the topic.
We found a neat wcf behavior that, we thought, would fix our problem.
It looked like it handles Bootstrap binding matters!
Here is a part where it searches for Token Parameters in a context of a TransportSecurityBindingElement:
//If the securityBindingElement's type is TransportSecurityBindingElement
if (securityBindingElement is TransportSecurityBindingElement)
{
foreach (SecurityTokenParameters securityTokenParameters in
securityBindingElement.EndpointSupportingTokenParameters.Endorsing)
{
//Gets it from the EndpointSupportingTokenParameters.Endorsing property
if (securityTokenParameters is SecureConversationSecurityTokenParameters)
{
secureConversationSecurityTokenParameters =
securityTokenParameters as SecureConversationSecurityTokenParameters;
break;
}
}
}
Note the 'securityBindingElement.EndpointSupportingTokenParameters.Endorsing'...
In our situation (basicHttpBinding, TransportWithMessageCredential, Https...), this collection is however empty!
So, no way to retrieve the securityTokenParameters, thus impossible to set the maxClockSkew.
Questions:
Are our bindings incorrect in a SL + WCF + HTTPS context?
Is it normal to not find any way to set the maxClockSkew on a bootstrap element in a TransportSecurityBindingElement?
Are we the only company doing HTTPS Silverlight app with customers that might not be on the exact same time (with +- 5 minutes offset) ?
Why does it seem to be quite an adventure to fix such trivial configuration?
Any help would be appreciated!
The following code snippet lets you set the maxClockSkew on the TransportSecurityBindingElement. My solution is an Outlook Add-in + WCF operating in http and https contexts, so although not the same context as yours its similar.
Your bindings look correct to me.
Here's the code snippet
WSHttpBinding wsSecureBinding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential, false);
wsSecureBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
wsSecureBinding.Security.Message.EstablishSecurityContext = true;
wsSecureBinding.Security.Message.NegotiateServiceCredential = true;
wsSecureBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
wsSecureBinding.ReaderQuotas.MaxStringContentLength = 500000;
wsSecureBinding.ReceiveTimeout =
wsSecureBinding.SendTimeout = new TimeSpan(0, 5, 0);
CustomBinding secureCustomBinding = new CustomBinding(wsSecureBinding);
TimeSpan clockSkew = new TimeSpan(0, 15, 0);
TransportSecurityBindingElement tsecurity = secureCustomBinding.Elements.Find();
SecureConversationSecurityTokenParameters secureTokenParams = (SecureConversationSecurityTokenParameters)tsecurity.EndpointSupportingTokenParameters.Endorsing.OfType().FirstOrDefault();
if (secureTokenParams != null)
{
SecurityBindingElement bootstrap = secureTokenParams.BootstrapSecurityBindingElement;
// Set the MaxClockSkew on the bootstrap element.
bootstrap.LocalClientSettings.MaxClockSkew = clockSkew;
bootstrap.LocalServiceSettings.MaxClockSkew = clockSkew;
}
The clock skew only matters as you are using UserName client credentials and some users either like their computer clocks not being the correct time, or they don't care
Yes, WCF configuration is always an adventure you'd rather not do.
We are running into the same problem here!!! For further discussion, if this post can help, the code where it searches for Token Parameter is taken from this site
http://issues.castleproject.org/_persistent/MaxClockSkewBehavior.cs?file=44-1075&v=0&c=true
Have you tried changing to custom binding in config (instead of code) and changing maxClockSkew there? See e.g. config samples in http://social.msdn.microsoft.com/forums/en-US/wcf/thread/0e8c30ab-e5a0-40b1-9722-c1b20a09c8ad/

Resources