I've encountered a problem with the XBAP Script Interop feature that was added in WPF 4. It involves a combination of the following:
Accessing members of a script object from .NET
Running .NET code in a callback invoked from JavaScript
Running in Partial trust
This seems to be a "pick any two" scenario... If I try and do all three of those things, I get a SecurityException.
For example, combining 1 and 3 is easy. I can put this into my hosting web page's script:
function ReturnSomething()
{
return { Foo: "Hello", Bar: 42 };
}
And then in, say, a button click handler in my WPF code behind, I can do this:
dynamic script = BrowserInteropHelper.HostScript;
if (script != null)
{
dynamic result = script.ReturnSomething();
string foo = result.Foo;
int bar = result.Bar;
// go on to do something useful with foo and bar...
}
That works fine, even in a partial trust deployment. (I'm using the default ClickOnce security settings offered by the WPF Browser Application template in Visual Studio 2010, which debugs the XBAP as though it were running in the Internet zone.) So far, so good.
I can also combine 2 and 3. To make my .NET method callable from JavaScript, sadly we can't just pass a delegate, we have to do this:
[ComVisible(true)]
public class CallbackClass
{
public string MyMethod(int arg)
{
return "Value: " + arg;
}
}
and then I can declare a JavaScript method that looks like this:
function CallMethod(obj)
{
var result = obj.MyMethod(42);
var myElement = document.getElementById("myElement");
myElement.innerText = "Result: " + result;
}
and now in, say, a WPF button click handler, I can do this:
script.CallMethod(new CallbackClass());
So my WPF code calls (via BrowserInteropHelper.HostScript) my JavaScript CallMethod function, which in turn calls my .NET code back - specifically, it calls the MyMethod method exposed by my CallbackClass. (Or I could mark the callback method as a default method with a [DispId(0)] attribute, which would let me simplify the JavaScript code - the script could treat the argument itself as a method. Either approach yields the same results.)
The MyMethod callback is successfully called. I can see in the debugger that the argument passed from JavaScript (42) is getting through correctly (having been properly coerced to an int). And when my method returns, the string that it returns ends up in my HTML UI thanks to the rest of the CallMethod function.
Great - so we can do 2 and 3.
But what about combining all three? I want to modify my callback class so that it can work with script objects just like the one returned by my first snippet, the ReturnSomething function. We know that it's perfectly possible to work with such objects because that first example succeded. So you'd think I could do this:
[ComVisible(true)]
public class CallbackClass
{
public string MyMethod(dynamic arg)
{
return "Foo: " + arg.Foo + ", Bar: " + arg.Bar;
}
}
and then modify my JavaScript to look like this:
function CallMethod(obj)
{
var result = obj.MyMethod({ Foo: "Hello", Bar: 42 });
var myElement = document.getElementById("myElement");
myElement.innerText = "Result: " + result;
}
and then call the method from my WPF button click handler as before:
script.CallMethod(new CallbackClass());
this successfully calls the JavaScript CallMethod function, which successfully calls back the MyMethod C# method, but when that method attempts to retrieve the arg.Foo property, I get a SecurityException with a message of RequestFailed. Here's the call stack:
at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
at System.Security.CodeAccessSecurityEngine.Check(PermissionSet permSet, StackCrawlMark& stackMark)
at System.Security.PermissionSet.Demand()
at System.Dynamic.ComBinder.TryBindGetMember(GetMemberBinder binder, DynamicMetaObject instance, DynamicMetaObject& result, Boolean delayInvocation)
at Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder.FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
at System.Dynamic.DynamicMetaObject.BindGetMember(GetMemberBinder binder)
at System.Dynamic.GetMemberBinder.Bind(DynamicMetaObject target, DynamicMetaObject[] args)
at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args)
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at XBapDemo.CallbackClass.MyMethod(Object arg)
That's the whole trace as reported by the exception. And above CallbackClass.MyMethod, Visual Studio is showing two lots of [Native to Managed Transition] and an [AppDomain Transition] - so that's the whole of the stack. (Apparently we're on a different thread now. This callback is happening on what the Threads panel describes as a Worker Thread - I can see that the Main Thread is still sat inside my WPF button click handler, waiting for the call to the JavaScript CallMethod function to return.)
Apparently the problem is that the DLR has ended up wrapping the JavaScript object in the ComBinder which demands full trust. But in the earlier case where I called a JavaScript method via HostScript and it returned me an object, the HostScript wrapped it in a System.Windows.Interop.DynamicScriptObject for me.
The DynamicScriptObject class is specific to WPFs XBAP script interop - it's not part of the usual DLR types, and it's defined in PresentationFramework.dll. As far as I can tell, one of the jobs it does is to make it possible to use C#'s dynamic keyword to access JavaScript properties without needing full trust, even though those properties are being accessed through COM interop (which usually requires full trust) under the covers.
As far as I can tell, the problem is that you only get these DynamicScriptObject wrappers for objects that are returned from other DynamicScriptObject instances (such as HostScript). With callbacks, that wrapping doesn't seem to occur. In my callback, I'm getting the sort of dynamic wrapper C# would normally give me in plain old COM interop scenarios, at which point, it demands that I have full trust.
Running it with full trust works fine - that would be the "1 and 2" combination from the list above. But I don't want to have full trust. (I want 1, 2, and 3.) And outside of callback situations, I can access JavaScript object members just fine. It seems inconsistent that I can access a JavaScript object just fine most of the time, but accessing an identical object in a callback is forbidden.
Is there a way around this? Or am I doomed to run my code in full trust if I want to do anything interesting in a callback?
I haven't done XBAP in a while, but I am curious if it is the dynamic type that could be causing the issue. Try changing the dynamic parameter to type object and see if it will work.
[ComVisible(true)]
public class CallbackClass
{
public string MyMethod(object arg)
{
return "Arg is: " + arg.ToString();
}
}
Related
My questions are many. Since I saw. NET 4.5, I was very impressed. Unfortunately all my projects are .NET 4.0 and I am not thinking about migrating. So I would like to simplify my code.
Currently, most of my code that usually take enough time to freeze the screen, I do the following:
BackgroundWorker bd = new BackgroundWorker();
bd.DoWork += (a, r) =>
{
r.Result = ProcessMethod(r.Argument);
};
bd.RunWorkerCompleted += (a, r) =>
{
UpdateView(r.Result);
};
bd.RunWorkerAsync(args);
Honestly, I'm tired of it. And that becomes a big problem when there is a logic complex user interaction.
I wonder, how to simplify this logic? (Remember that I'm with. Net 4.0) I noticed a few things by google, but not found anything easy to implement and suitable for my needs.
I thought this solution below:
var foo = args as Foo;
var result = AsyncHelper.CustomInvoke<Foo>(ProcessMethod, foo);
UpdateView(result);
public static class AsyncHelper
{
public static T CustomInvoke<T>(Func<T, T> func, T param) where T : class
{
T result = null;
DispatcherFrame frame = new DispatcherFrame();
Task.Factory.StartNew(() =>
{
result = func(param);
frame.Continue = false;
});
Dispatcher.PushFrame(frame);
return result;
}
}
I am not sure about the impact is on manipulating the dispatcher frame.
But I know That it would work very well, for example, I could use it in all the events of controls without bothering to freeze the screen.
My knowledge about generic types, covariance, contravariance is limited, maybe this code can be improved.
I thought of other things using Task.Factory.StartNew and Dispatcher.Invoke, but nothing that seems interesting and simple to use. Can anyone give me some light?
You should just use the Task Parallel Library (TPL). The key is specifying the TaskScheduler for the current SynchronizationContext for any continuations in which you update the UI. For example:
Task.Factory.StartNew(() =>
{
return ProcessMethod(yourArgument);
})
.ContinueWith(antecedent =>
{
UpdateView(antecedent.Result);
},
TaskScheduler.FromCurrentSynchronizationContext());
Aside from some exception handling when accessing the antecedent's Result property, that's all there is too it. By using FromCurrentSynchronizationContext() the ambient SynchronizationContext that comes from WPF (i.e. the DispatcherSynchronizationContext) will be used to execute the continuation. This is the same as calling Dispatcher.[Begin]Invoke, but you are completely abstracted from it.
If you wanted to get even "cleaner", if you control ProcessMethod I would actually rewrite that to return a Task and let it own how that gets spun up (can still use StartNew internally). That way you abstract the caller from the async execution decisions that ProcessMethod might want to make on its own and instead they only have to worry about chaining on a continuation to wait for the result.
UPDATE 5/22/2013
It should be noted that with the advent of .NET 4.5 and the async language support in C# this prescribed technique is outdated and you can simply rely on those features to execute a specific task using await Task.Run and then execution after that will take place on the Dispatcher thread again automagically. So something like this:
MyResultType processingResult = await Task.Run(() =>
{
return ProcessMethod(yourArgument);
});
UpdateView(processingResult);
How about encapsulating the code that is always the same in a reusable component? You could create a Freezable which implements ICommand, exposes a property of Type DoWorkEventHandler and a Result property. On ICommand.Executed, it would create a BackgroundWorker and wire up the delegates for DoWork and Completed, using the value of the DoWorkEventHandler as event handler, and handling Completed in a way that it sets its own Result property to the result returned in the event.
You'd configure the component in XAML, using a converter to bind the DoWorkEventHandler property to a method on the ViewModel (I assume you've got one), and bind your View to the component's Result property, so it gets updated automatically when Result does a change notification.
The advantages of this solution are: it is reusable, and it works with XAML only, so no more glue code in your ViewModel just for handling BackgroundWorkers. If you don't need your background process to report progress, it could even be unaware that it runs on a background thread, so you can decide in the XAML whether you want to call a method synchronously or asynchronously.
A few months have passed, but could this help you?
Using async/await without .NET Framework 4.5
I have a C++ application in which I'm trying to show a WPF form (named WSWindow), specifically one that inherits from the System.Windows.Window class so that I can get the window handle using the WindowInteropHelper class.
My problem is that whenever I make the call to the method below, the application crashes.
public IntPtr GetHWND()
{
if (ivWindow == null)
{
ivWindow = new WSWindow();
ivWindow.WindowStartupLocation = WindowStartupLocation.Manual;
ivWindow.Show();
}
IntPtr handle = new WindowInteropHelper(ivWindow).Handle;
return handle;
}
I believe the WSWindow constructor is causing the crash. On the C# side of things there's a WSService class that calls the WSWindow constructor, and if I put the WSWindow constructor in the WSService constructor, the C++ app crashes on calling the WSService constructor (something that works fine when the WSService constructor does not contain the WSWindow constructor). Also, in addition to calling the above method, I've tried the following in the C++ app:
WSWindow^ w = gcnew WSWindow();
and there are log lines immediately after this line that don't get written to the log file.
In the WSWindow contructor, there's a call to InitializeComponents, which is generated code in the WSWindow.g.cs file:
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri("/Project_Name;component/wswindow.xaml", System.UriKind.Relative);
#line 1 "..\..\WSWindow.xaml"
System.Windows.Application.LoadComponent(this, resourceLocater);
#line default
#line hidden
}
At first I thought maybe the call to LoadComponent was failing because the uri couldn't be resolved, but I added a log line in the WSWindow constructor before the call to InitializeComponent() which gets written when the WSWindow is created from a Windows Forms test app, but not when the WSWindow is created by a call from the C++ app, so it seems like nothing in the WSWindow constructor even gets executed, it just crashes right away.
There's no problem with references that I can tell; I've written a couple test methods, one that returns an int, one a simple custom Window object with width/height members and successfully called both from the C++ app.
I've also successfully retrieved the handle to the WSWindow when it is compiled as a WPF app and run before launching the C++ app, but I need to be able to create the WSWindow from a call within the C++ app.
I've spent days on this problem trying to figure out why the crash is occurring with no luck. I'm hoping someone that reads this knows something about WPF that could be causing this issue, or a known issue between C++/CLI and WPF controls. I'm totally out of ideas.
Additional info: When I start the C++ app and attach VS to the process, nothing shows up in the call stack (a separate problem for me to work on), but I noticed a couple exceptions that look like they might be related:
First-chance exception at 0x75a8b9bc (KernelBase.dll) in MM.EXE: Microsoft C++ exception: HRException at memory location 0x06e6b158..
First-chance exception at 0x75a8b9bc (KernelBase.dll) in MM.EXE: Microsoft C++ exception: [rethrow] at memory location 0x00000000..
First-chance exception at 0x75a8b9bc (KernelBase.dll) in MM.EXE: Microsoft C++ exception: HRException at memory location 0x06e6b608..
First-chance exception at 0x75a8b9bc (KernelBase.dll) in MM.EXE: Microsoft C++ exception: [rethrow] at memory location 0x00000000..
The solution was that I needed to mark the thread making the call to create/show the WPF Window with the [STAThread] attribute.
I have another newbie question regarding registering additional dependencies within TinyIoc for use within NancyFX.
I am continuing to get the following exceptions when running the application...
Unable to resolve type: AdvancedSearchService.Interfaces.IResponseFactory
Exception Details: TinyIoC.TinyIoCResolutionException: Unable to resolve type: AdvancedSearchService.Interfaces.IResponseFactory
Source Error:
Line 25: var container = TinyIoCContainer.Current;
Line 26:
Line 27: _responseFactory = container.Resolve<IResponseFactory>();
Line 28:
Line 29:
I am currently registering my dependencies incorrectly, but I cannot seem to figure out the correct way. Below is my code within my custom bootstrapper. Also note that I am not currently calling the base.ConfigureRequestContainer method because I cannot seem to figure out how to get the current context to pass into it.
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
container.Register<IRavenSessionManager>(new RavenSessionManager());
base.ConfigureApplicationContainer(container);
ConfigureRequestContainer(container);
}
protected void ConfigureRequestContainer(TinyIoCContainer applicationContainer)
{
var requestContainer = applicationContainer.GetChildContainer();
requestContainer.Register<ISearchRepository>(new SearchRepository(requestContainer.Resolve<IRavenSessionManager>().GetSession()));
requestContainer.Register<IResponseFactory>(new ResponseFactory(requestContainer.Resolve<ISearchRepository>()));
//base.ConfigureRequestContainer(requestContainer,[I NEED THE CONTEXT])
}
Any help would really be appreciated...apparently my ignorance has no limits :)
Ok, not 100% sure where to start.. you don't need the context because you're doing it wrong :-)
Firstly, why are you calling "configure request container" at all, and why are you creating a child container? You don't do that :-) There are two scopes, application scope, configured by overriding ConfigureApplicationContainer, and request scope, configured by overriding ConfigureRequestContainer, you don't call them yourself, you just override them depending on how you want to scope your objects.
Secondly, the default Nancy bootstrapper will "autoregister" everything it can in its default implementation of ConfigureApplicationContainer. By calling "base" after you've made a manual registration you are effectively copying over your original registration by autoregister. Either don't call base, or call it before you do your manual registrations. And, again, don't call ConfigureRequestContainer from your ConfigureApplicationContainer :-)
If you don't care about everything being application scoped (so singetons get the same instance for each request) then you don't need any of this, you can just rely on autoregister.
You're currently constructing your objects manually and putting them into the container, that seems a rather odd way to do it. Normally you'd just register the types and let the container handle instantiating as and when it needs to.
You're not overriding ConfigureRequestContainer, you are just creating a new method (with a different signature).
So, what you probably want is something like:
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
// Autoregister will actually do this for us, so we don't need this line,
// but I'll keep it here to demonstrate. By Default anything registered
// against an interface will be a singleton instance.
container.Register<IRavenSessionManager, RavenSessionManager>();
}
// Need to override this, not just make a new method
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
// Get our session manager - this will "bubble up" to the parent container
// and get our application scope singleton
var session = container.Resolve<IRavenSessionManager>().GetSession();
// We can put this in context.items and it will be disposed when the request ends
// assuming it implements IDisposable.
context.Items["RavenSession"] = session;
// Just guessing what this type is called
container.Register<IRavenSession>(session);
container.Register<ISearchRepository, SearchRepository>();
container.Register<IResponseFactory, ResponseFactory>();
}
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)
I have written a webmethod that returns the list of the Users althought the service works fine, when I call it from the page the methods in the webservice have return type as void.
What you might be thrown off by is that web service calls in Silverlight must be handled asynchronously.
When you define a WebMethod, say for example you have one called DoWork on a Class called WorkMan. Your code in the Silverlight would end up looking like:
WorkManSoapClient client = new WorkManSoapClient();
client.DoWorkCompleted += new EventHandler<DoWorkCompletedEventArgs>(this.DoWorkCompleteHandler); // where DoWorkCompletedHandler handles the callback.
Then you call your actual method and allow the callback to process the result.
client.DoWorkAsync();
If your webmethod returns a value, your EventArg object will have a Result property that you can leverage for the result.
One final note: a personal stylistic thing but I like lambda expressions rather than generating a whole new method for the callback. I might write something like the following:
WorkManSoapClient client = new WorkManSoapClient();
client.DoWorkCompleted += (s,e) => {
if(e.Result != null){
object foo = e.Result;
}
};
client.DoWorkAsync();