Issue intercepting property in Silverlight application - silverlight

I am using Ninject as DI container in a Silverlight application. Now I am extending the application to support interception and started integrating DynamicProxy2 extension for Ninject. I am trying to intercept call to properties on a ViewModel and ending up getting following exception:
“Attempt to access the method failed: System.Reflection.Emit.DynamicMethod..ctor(System.String, System.Type, System.Type[], System.Reflection.Module, Boolean)”
This exception is thrown when invocation.Proceed() method is called. I tried two implementations of the interceptor and they both fail
public class NotifyPropertyChangedInterceptor: SimpleInterceptor
{
protected override void AfterInvoke(IInvocation invocation)
{
var model = (IAutoNotifyPropertyChanged)invocation.Request.Proxy;
model.OnPropertyChanged(invocation.Request.Method.Name.Substring("set_".Length));
}
}
public class NotifyPropertyChangedInterceptor: IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
var model = (IAutoNotifyPropertyChanged)invocation.Request.Proxy;
model.OnPropertyChanged(invocation.Request.Method.Name.Substring("set_".Length));
}
}
I want to call OnPropertyChanged method on the ViewModel when property value is set.
I am using Attribute based interception.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class NotifyPropertyChangedAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
if(request.Method.Name.StartsWith("set_"))
return request.Context.Kernel.Get<NotifyPropertyChangedInterceptor>();
return null;
}
}
I tested the implementation with a Console Application and it works alright.
I also noted in Console Application as long as I had Ninject.Extensions.Interception.DynamicProxy2.dll in same folder as Ninject.dll I did not have to explicitly load DynamicProxy2Module into the Kernel, where as I had to explicitly load it for Silverlight application as follows:
IKernel kernel = new StandardKernel(new DIModules(), new DynamicProxy2Module());
Could someone please help? Thanks

Reflection can be really tricky in silverlight because of security issues.
Check Gabe's answer for this question, it's the same problem.
The good news is that you can achieve the same functionality you want using dynamic instead of proxies. Just extend your ViewModel from DynamicObject and override the TrySetMember method.
I hope it helps :)

Related

MVVM Light for Xamarin Forms and WPF

I'm trying to make an cross-plattform app, that will work for Xamarin.Forms and WPF (like this: https://github.com/C0D3Name/XamFormsWpf) in combination with MVVM light.
MVVM Light is quite new to me and i didn't find a clear tutorial for what i want to do. On Xamarin.Forms the DependencyInjection is done by
SQLiteConnection database = DependencyService.Get<ISQLite>().GetConnection("db.sqlite");
How is this done in MVVM light? Do i have to pass the different plattform-implementations of ISQLite in as parameter?
I already created the ViewModelLocator in my PCL:
public class ViewModelLocator
{
/// <summary>
/// Register all the used ViewModels, Services et. al. witht the IoC Container
/// </summary>
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
// My DataService is using the connection from ISQlite
SimpleIoc.Default.Register<IDataService, DataService>();
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
}
public interface ISQLite
{
SQLiteConnection GetConnection(string sqliteFilename);
}
As far as i understood the SimpleIoc, i have to register the interface to a concrete implementation, but how does my DataService know about the correct ISQLite Implementation?
I hope my question is understandable.
From official docs:
SimpleIoc - A very simple IOC container with basic functionality needed to register and resolve instances.
DependencyService - Xamarin.Forms allows developers to define behavior in platform-specific projects. DependencyService then finds the right platform implementation, allowing shared code to access the native functionality.
So you would want to use SimpleIoc to create your PCL dependency injection graph (IDataService for example)
And you will have to use DependencyService to provide platform specific functionality. One example for DependencyService use would be loading a html file located on the device into webview. Since the locations of assets on iOS and Android are different you will have add platform specific implementation for base url and then use DependencyService in your pcl. Another example would be IO.
So in your case if you need platform specific implementations of ISQlite you will have to use DependencyService. If not you may want (or not) to use SimpleIoc to add concrete implementation of ISQlite interface to your dependency graph.
Hope that helps.
Also have a look at Akavache. We use it with a great success in Xamarin.Forms projects.
Finally i found a working solution. The (async) Sqlite-Connection is used as parameter for my ViewModelLocator
public class App : Application
{
private static ViewModelLocator locator;
public static ViewModelLocator Locator
{
get
{
if (locator == null)
{
var connection = DependencyService.Get<ISQLite>().GetConnection("db.sqlite");
locator = new ViewModelLocator(connection);
}
return locator;
}
}
}
...and the locator injects the connection into the DataService constructor:
public class ViewModelLocator
{
public ViewModelLocator(SQLiteConnectionWithLock connection)
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<IDataService>(() => new DataService(connection));
// ViewModels
SimpleIoc.Default.Register<MainViewModel>();
}
public MainViewModel Main => ServiceLocator.Current.GetInstance<MainViewModel>();
}

Optional Dependency at Composition Root

I've written a WPF app that has two different main windows. I don't know which one to launch until runtime by looking up what kind of user is using the program in a database. The code I currently have works but Castle Windsor is doing tons of extra work by newing up the object graphs for both kinds of windows.
private readonly IMainWindow _mainWindow;
private readonly ISimplifiedMainWindow _simplifiedMainWindow;
public MainClass(
IMainWindow mainWindow,
ISimplifiedMainWindow simplifiedMainWindow)
{
_mainWindow = mainWindow;
_simplifiedMainWindow = simplifiedMainWindow;
}
public RunApp()
{ // pseudocode
if (user is fullUser) _mainWindow.Show();
else _simplifiedMainWindow.Show();
}
How do I defer creation of my window objects without resorting to making an abstract factory that will basically duplicate what Castle Windsor does anyway?
A factory is in fact the solution I'd recommend (and a solution I've successfully used multiple times in the past to solve this very problem).
I wouldn't implement the factory myself though, let Windsor do it (via a Typed Factory).
public interface IWindowFactory
{
IMainWindow FullUserWindow();
ISimplifiedMainWindow SimplifiedUserWindow();
//optionally
void DestroyWindow(IWindow window);
}
Now you just need to tell Windsor to build a factory for that interface
container.AddFacility<TypedFactoryFacility>();
// later on, in your installer
container.Register(Component.For<IWindowFactory>()
.AsFactory()
.LifestyleTransient());
and your app code changes to:
public RunApp()
{ // pseudocode
if (user is fullUser) Show(factory.FullUserWindow());
else Show(factory.SimplifiedUserWindow());
}

Registering Startup Class In Nancy Using AutoFac Bootstrapper

I've been reading through a lot of the Jabbr code to learn Nancy and trying to implement many of the same patterns in my own application. One of the things I can't seem to get working is the concept of an on application start class. The Jabbr code base has an App_Start folder with a Startup.cs file (here) in it with the following implementation.
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
...
SetupNancy(kernel, app);
...
}
}
private static void SetupNancy(IKernel kernel, IAppBuilder app)
{
var bootstrapper = new JabbRNinjectNancyBootstrapper(kernel);
app.UseNancy(bootstrapper);
}
When I tried to do something similar to that in my project the Startup.cs file was just ignored. I searched the Jabbr code base to see if it was used anywhere but I wasn't able to find anything and the only differences I could see is Jabbr uses Ninject while I wanted to use AutoFac
Is there a way to register a startup class in nancy?
Take a look at my project over on GitHub, you'll be interested in the Spike branch and may have to unload the ChainLink.Web project to run I can't remember.
I had some trouble finding a way to configure the ILifetimeScope even after reading the accepted answer here by TheCodeJunkie. Here's how you do the actual configuration:
In the bootstrapper class derived from the AutofacNancyBootstrapper, to actually configure the request container, you update the ILifetimeScope's component registry.
protected override void ConfigureRequestContainer(
ILifetimeScope container, NancyContext context)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDependency>();
builder.Update(container.ComponentRegistry);
}
The application container can be updated similarly in the ConfigureApplicationContainer override.
You should install the Nancy.Bootstrappers.Autofac nuget, inherit from the AutofacNancyBootstrapper type and override the appropriate method (depending on your lifetime scope requirements: application or request). For more info check the readme file https://github.com/nancyfx/nancy.bootstrappers.autofac
HTH
After following the advice from TheCodeJunkie you can use the Update method on the ILifetimeScope container parameter which gives you a ContainerBuilder through an Action:
protected override void ConfigureRequestContainer(ILifetimeScope container, NancyContext context)
{
container.Update(builder =>
{
builder.RegisterType<MyType>();
});
}

Silverlight 4, subclassing WebClient

Following an advice, I saw at several web pages (for example Using CookieContainer with WebClient class), I subclassed WebClient class to use a cookie with it:
public class MyWebClient : System.Net.WebClient
{
}
Now, when I initialize MyWebClient:
MyWebClient wc = new MyWebClient();
it throws TypeLoadException. My OS is Windows 7 (japanese), so error message is not in english; I see it is related to security rules. What might be the problem?
WebClient's constructor is marked with the SecuritySafeCritical attribute. And it looks like that is what is causing the security exception. I tried applying that same attribute to MyWebClient's constructor but that didn't work. From what I've read, this kind of thing just isn't allowed in Silverlight. For example, see this other question.
For reference, the exact exception message is:
System.TypeLoadException
Inheritance security rules violated while
overriding member: 'MyWebClient..ctor()'. Security accessibility of
the overriding method must match the security accessibility of the
method being overriden.
I wish there was a better answer...
You need to implement a default constructor with the SecuritySafeCritical attribute. Had this problem today and that was the solution.
public class MyWebClient : System.Net.WebClient
{
[SecuritySafeCritical]
public MyWebClient() : base() {}
}

AppDomain.GetData method not accessible?

I am developing a Silverlight 3 application and I would like to delegate all unexpected error handling in a single instance of a class I have named ErrorHandler. This class has one method named HandleApplicationException, plus a couple of other methods to handle more specialized errors.
In my application I am using Unity for dependency injection, but since I want the error handling object to be available even when the Unity container is not yet set up, I register the object as AppDomain global data in the App class constructor, this way:
public App()
{
this.Startup += this.Application_Startup;
this.Exit += this.Application_Exit;
this.UnhandledException += this.Application_UnhandledException;
AppDomain.CurrentDomain.SetData("ErrorHandler", new ErrorHandler());
InitializeComponent();
}
And in case of unhandled exception, I retrieve the error handler object and use it this way:
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
e.Handled = true;
var errorHandler = AppDomain.CurrentDomain.GetData("ErrorHandler") as ErrorHandler;
Debug.Assert(errorHandler != null, "No ErrorHandler registered.");
errorHandler.HandleApplicationException(e.ExceptionObject);
}
The problem is that the AppDomain.GetData method in the Application_UnhandledException method is throwing a MethodAccessException. I don't understand why, as I am just invoking a public method on the AppDomain class. I have used a similar approach in other applications and it worked fine (anyway these were not Silverlight applications).
So, what's going on? Am I doing something wrong?
Ok, I got it. From MSDN documentation:
This member has a
SecurityCriticalAttribute attribute,
which restricts it to internal use by
the .NET Framework for Silverlight
class library. Application code that
uses this member throws a
MethodAccessException.
I have resorted to storing the error handler in a public property in the App class, then I access it using ((App)Application.Current).ErrorHandler. I don't like doing things this way but I suppose it is ok in this special case.
Why can't you just use a static instance of ErrorHandler? I.e. have something like ErrorHandler.Current?
It looks like you're trying to manually construct a poor man's IoC framework to be honest.
Consider doing some research on Unity/Ninject and see for yourself why strongly-typed decoupling is better.

Resources