PRISM Modular dependencies - xamarin.forms

I have a question regarding module dependencies to other module. I have researched regarding about how different modules communicate with each other but I am not sure what to use and I quite need some clarifications how am I going to use them properly.
How do I load modules depending with each other? e.g. Module A needs to navigate to Module B one of the views of it. Should I load Module A first and then load Module B when I need to navigate to it?
How do I set dependencies with each module? Should I configure them inside the ModuleCatalog resulting into moduleCatalog.AddModule<ModuleB>("ModuleB", InitializationMode.OnDemand, "ModuleA"); or should I do: [ModuleDependency(ModuleA)] on top of the Module B class
Module A needs to navigate to one of the pages in Module B and I have to pass navigation parameters into Module B. Should I use a shared service or an event aggregator ? though as much as possible I want to lessen the use of an event aggregator

This is the beauty of Prism in my opinion.
You have a lot of flexibility when it comes to where to load the modules.
In the past, I have used the IModuleManager which I can inject into a ViewModel of any module and from there I can call the Load Method.
The load method takes in the string name of the module that you have registered.
When registering I have also set the Load Type to onDemand so the module is only loaded only when I specifically call the load method.
So in your scenario, you could load Module B whenever you need to in Module A.
It could be triggered by some business logic for your application.
To answer your second question you can then simply just pass your parameters using the navigation parameters functionality of the Navigation service
var param = new NavigationParameters();
param.Add("trip", someObject);
await NavigationService.NavigateAsync("TripDetailsPage", param);
EDIT:
So if you want to know whether a Module has been loaded or not you could do something like the following:
public class ModuleService : IModuleService
{
private readonly IModuleCatalog _moduleCatalog;
private readonly IModuleManager _moduleManager;
public ModuleService(IModuleCatalog moduleCatalog, IModuleManager moduleManager)
{
_moduleCatalog = moduleCatalog;
_moduleManager = moduleManager;
}
public bool Exists(string moduleName)
{
return _moduleCatalog.Modules.Any(x => x.ModuleName == moduleName);
}
public bool Initialized(string moduleName)
{
return _moduleCatalog.Modules.Any(x => x.ModuleName == moduleName && x.State == ModuleState.Initialized);
}
public void LoadModule(string moduleName)
{
_moduleManager.LoadModule(moduleName);
}
}
So by combining the functionality of the ModuleManager and the Module Catalog, I can check if a module is already loaded using the modules ModuleState property

Related

Autofac Multiple Regsistrations to Single service. Simple Injector -> Autofac translation

I've developed a CQRS style database access framework based on Tripod and other inspirations but targeting .NET Standard and simplifying for easier use. I want to split the IoC into separate integration packages so consumers can get the type registration I'm currently doing internally easily without being locked into a specific IoC container. My issue is I've only really worked closely with SimpleInjector so not familiar with other systems and their nuances around how they handle specific scenarios. I have an iminent need to support Autofac so thought I'd try here to see if anyone can translate.
I have the following Simple Injector CompositionRoot static class:
public static void RegisterDatabase(this Container container, DbContextOptions<EntityDbContext> dbContextOptions, params Assembly[] assemblies)
{
var scopedLifeStyle = container.Options.DefaultScopedLifestyle;
//container.Register<ICreateDbModel, DefaultDbModelCreator>(scopedLifeStyle); // lifestyle c
container.RegisterInitializer<EntityDbContext>( //(container.InjectProperties);
handlerToInitialise => handlerToInitialise.ModelCreator = new DefaultDbModelCreator()
);
// Setup DbContext
var ctxReg = scopedLifeStyle.CreateRegistration(
() => new EntityDbContext(dbContextOptions),
container);
container.AddRegistration<IUnitOfWork>(ctxReg);
container.AddRegistration<IReadEntities>(ctxReg);
container.AddRegistration<IWriteEntities>(ctxReg);
}
In ASP.NET Core solutions I invoke the above from Startup.Configure(...) with:
var optionsBuilder = new DbContextOptionsBuilder<EntityDbContext>()
//.UseInMemoryDatabase("Snoogans");
.UseSqlServer(_config.GetConnectionString("DefaultConnection"));
container.RegisterDatabase(optionsBuilder.Options);
which allows me to switch out to an in memory database for unit testing if needed. EntityDbContext contains all my unit of work methods for calling onto the context without having to specify explicit DbSet for each table. The IUnitOfWork, IReadEntities and IWriteEntities interfaces all define methods on the EntityDbContext.
So I'm not sure how I'd go about making an Autofac module that allows scoped registration of the dbcontext with passed in DbContextOptions followed by multiple registrations of interfaces to this registration.
Does anyone know how this can be achieved?
I worked out the process and now have an AutoFac module. I was able to registermodule by instance of the class and also pass in the options when I instantiate. Because EntityDbContext implements the three interfaces I was registering separately in the Simple Injector scenario, AutoFac has the convenience of being able to just infer them and register with AsImplementedInterfaces()
public class EntityFrameworkModule : Module
{
private readonly DbContextOptions<EntityDbContext> _dbContextOptions;
public EntityFrameworkModule(DbContextOptions<EntityDbContext> dbContextOptions)
{
_dbContextOptions = dbContextOptions;
}
protected override void Load(ContainerBuilder builder)
{
// If the calling code hasn't already registered a custom
// ICreateDbModel then register the internal DefaultDbModelCreator
builder.RegisterType<DefaultDbModelCreator>()
.IfNotRegistered(typeof(ICreateDbModel))
.As<ICreateDbModel>();
// Expecting IUnitOfWork, IReadEntities and IWriteEntities to be registered with this call
builder.Register(c => new EntityDbContext(_dbContextOptions)
{
ModelCreator = c.Resolve<ICreateDbModel>()
})
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
}
}

ASP.NET Core Identity - UserManager and UserStore woes

I'm trying to implement the Identity system in an ASP.NET Core app (RC2 libraries) and there is a particular hangup that is driving me crazy.
First of all, I am not using EntityFramework. I'm not even using SQL. I'm backing up to RavenDB, so I need the implementation to be very specific to that; Which isn't a problem.
So I designed a RavenUserStore class, and it looks like this;
public class RavenUserStore<TUser> :
IUserStore<TUser>,
IUserLoginStore<TUser>,
IUserPasswordStore<TUser>,
IUserRoleStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserClaimStore<TUser>,
IUserLockoutStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserEmailStore<TUser> {
// ...
}
Works great on its own. I've implemented all the methods, etc. It's wonderful. Very clean and efficient.
Now, I go over to my web application and wire things up;
services.AddTransient<ILookupNormalizer>(s => new LowerInvariantLookupNormalizer());
services.AddTransient<IPasswordHasher<Member>>(s => new PasswordHasher<Member>());
services.AddTransient<IUserStore<Member>, RavenUserStore<Member>>();
services.AddIdentity<Member, Role>(o => {
o.Password.RequiredLength = 6;
o.Password.RequireDigit = true;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
})
.AddUserStore<RavenUserStore<Member>>()
.AddRoleStore<RavenRoleStore<Role>>();
So I go make a controller to use this, per all the samples I've seen, and the very core sample from the Identity Framework Github Repository
//... [PROPERTIES]...//
public AccountController(UserManager<Member> userManager, SignInManager<Member> signInManager) {
// ... [attach constructor parameters to properties] ...//
}
Alright, so I inspect the classes carefully.
UserManager<T> has a property Store,which is a type of IUserStore<T>.
So theoretically.. if the dependency injection resolves types of IUserStore<T> to RavenUserStore<T> when they are injected through a constructor.. shouldn't that mean that the UserManager<T> gets a RavenUserStore<T> as its Store property?
I thought it would too; But when I call methods on the UserManager, it DOES NOT call the ones on my RavenUserStore. Why is this? What can I do?
Do I really have to ALSO make a custom UserManager class and do all of those methods AGAIN?
You need to add your own custom providers before calling services.AddIdentity(). Internally, AddIdentity uses TryAddScoped() which only adds the default items if they don't already exist in the services container.
So just putting the call to AddIdentity() after you registered all your custom implementations should mean that they will take precedence as you expect.

Event not working

I am new to Tridion Event System. I have written a small code.
[TcmExtension("MyEventHandlerExtension")]
public class EH : TcmExtension
{
public EH()
{
Subscribe();
}
public void Subscribe()
{
//EventSystem.Subscribe<Component, DeleteEventArgs>(HandlerForInitiated, EventPhases.Initiated);
EventSystem.Subscribe<Tridion.ContentManager.CommunicationManagement.Page, Tridion.ContentManager.Extensibility.Events.PublishOrUnPublishEventArgs>(HandlerForCommitted, EventPhases.All);
}
private void HandlerForCommitted(IdentifiableObject subject, PublishOrUnPublishEventArgs args, EventPhases phase)
{
TDSE obj = new TDSE();
Tridion.ContentManager.Interop.TDS.Publication pub = obj.GetPublication("tcm:0-150-1");
Tridion.ContentManager.Interop.TDS.Page pubPage = obj.GetPage("tcm:150-12374-64", pub);
pubPage.Publish("tcm:0-1-65538", false, true, false, default(DateTime), default(DateTime), default(DateTime));
}
}
using this code i wanted to publish a page everytime when a publish and unpublish event occur.
I build this code and register its path in tridion config file .
But its not working.Please Help
Ok, first of all remove all your TDSE code, you should use TOM.NET. You can get session as subject.Session
Then make sure you have registered this extension in Tridion.ContentManager.config and restarted your system
And finally - if something doesn't work, just add simple code that will create a file in your HandlerForCommitted whenever event occurs, this way you will be able to see if your extension get executed.
The 2011 Event System uses the TOM.NET API and not the TOM API. Please do not create new TDSE objects in the 2011 Event System. Even though you can reference the old Interop libraries, there is no reason to do so with 2011. Using the TOM.NET libraries you should see better performance and also the code is future-proof.
Mihai Cadariu has a nice example where he uses TOM.NET to Publish a page from a Tridion Template. Adjusting the code to check for previewmode or publish mode and setting your own user and priority (instead of reading it from the current transaction) should work well.
Below code from http://yatb.mitza.net/2012/05/publishing-from-template-code-using.html
public void Publish(Engine engine, String tcmUri, User user, PublishPriority priority)
{
Session session = new Session(user.Title);
PublishInstruction publishInstruction = new PublishInstruction(session);
RenderInstruction renderInstruction = new RenderInstruction(session);
renderInstruction.RenderMode = RenderMode.Publish; // work around. needs to be specified for binaries.
publishInstruction.RenderInstruction = renderInstruction;
List<IdentifiableObject> items = new List<IdentifiableObject>() { session.GetObject(tcmUri) };
List<PublicationTarget> targets = new List<PublicationTarget>() { engine.PublishingContext.PublicationTarget };
PublishEngine.Publish(items, publishInstruction, targets, priority);
session.Dispose();
}
// called with
PublishTransaction currentTransaction = TemplateUtils.GetPublishTransaction(engine);
TemplateUtils.Publish(engine, itemUri, currentTransaction.Creator, currentTransaction.Priority);
Your code seems to have the three things I "normally" forget:
the class is public
it extends TcmExtension
it has a TcmExtension attribute
If you've registered the class correctly in the configuration file, it should just be a matter of restarting the relevant module(s). In this case I'd expect those to be the Publisher and TcmServiceHost services.
After restarting those modules and triggering a publish action, you should see an event being logged (in the Windows event viewer) that your extension is being loaded.
If that even shows, it means your assembly is being loaded into the relevant Tridion process and the class is being recognized and instantiated.
If at this stage your handler doesn't fire you may have to consider listening to a different event. Whenever I want to interact with the publishing, I end up listening for the SaveEventArgs of a PublishTransaction, instead of the PublishOrUnPublishEventArgs on the Page.

How do you access the public properties and methods of a loaded SWF

How would you go about calling the public properties and methods of a SWF you load in actionscript?
I have been using stackoverflow for years to answer my programming questions so I wanted to give back by writing a guide to an issue I had a lot of trouble figuring out. This is my first user guide so tell me if there is anything I can do to improve it.
One of the more powerful features of the flash engine is the ability to load flash programs within flash programs, through the use of the Loader class. Unfortunately communication with the loaded program is limited. While you can establish a LocalConnection object there is a limit to the traffic it can safely support.
A simple solution is to load the SWF file within your main program’s security domain. This has the benefit of exposing the public methods and properties of the loaded SWF to the loader and vice versa.
First extend the Loader class this class will be used to interact with the loaded file.
public class ParentChildLoader extends Loader
Next we must store the SWF file as a ByteArray. The variable path is a file path on the system. You could use a URLStream object instead of a FileStream for a http url.
var swfBytes:ByteArray = new ByteArray();
var file:File = new File(path);
if (file.exists)
{
var loadStream:FileStream = new FileStream();
loadStream.open(file, FileMode.READ);
loadStream.readBytes(swfBytes);
loadStream.close();
}
Now that we have the SWF stored as a ByteArray, we load the SWF into our security domain and listen for the complete event.
var context:LoaderContext = new LoaderContext();
context.allowLoadBytesCodeExecution = true;
addEventListener(Event.COMPLETE, onSwfLoad);
loadBytes(swfBytes, context);
If you want to access the loaded SWF’s properties from the loader use the content property.
Object(this.content).foo(bar);
Object(this.content).a = b;
If you want to access the loader’s public properties from the SWF use the parent property.
Object(this.parent).foo(bar);
Object(this.parent).a = b;
This has many practical applications from allowing re-usability of common functions to taking some of the programming load off your creative team. A note of caution; the loaded SWF exists within your main program’s security domain so it is key that you only load files which you trust with this method.
A cleaner way would be to use interfaces. Here's an example. Consists of two projects. Project 1 (PluginLoader) is your base app. Part of this project includes an AS3 Interface:
/* IPlugin.as */
package
{
public interface IPlugin
{
function getID():String;
function doStuff():void;
}
}
Then, your loaded swf in a second project (TestPlugin) implements the interface:
package
{
import flash.display.Sprite;
public class TestPlugin extends Sprite implements IPlugin
{
private const _ID:String = "TestPlugin";
public function getID():String {
return _ID;
}
public function doStuff():void {
trace('Test plugin: Doing Stuff');
}
}
}
The interface would be included in that project via source files or swc.
Then to load it (back in PluginLoader project):
public class PluginLoader extends Sprite
{
public function PluginLoader()
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loader.load(new URLRequest('plugins/TestPlugin.swf'));
}
private function completeHandler(e:Event):void {
var plugin:IPlugin = e.target.content as IPlugin;
trace(plugin.getID());
plugin.doStuff();
}
}
}
I would have to disagree with you on your approach. It is 'hackish' in my opinion. There is a reason why you have limited communication with loaded swfs, and that is because you don't know what they do and how they're suppose to be managed.
If you want to talk architecturally, this is a very bad way of trying to access information. The main application should not have to access properties within the loaded swf. If you're building a large scale application and the loaded swf (a module maybe?) needs information that the main app has, you should look into an application framework like Parsley which does dependency injection to give the data your loaded swf needs. It is a much cleaner approach and is architecturally sound.

Get instance of type inheriting from base class, implementing interface, using StructureMap

Continuing on my quest for a good plugin implementation I have been testing the StructureMap assembly scanning features.
All plugins will inherit from abstract class PluginBase. This will provide access to common application services such as logging. Depending on it's function, each plugin may then implement additional interfaces, for example, IStartUpTask.
I am initializing my plugins like so:
Scan(x => {
x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"),
assembly => assembly.GetName().Name.Contains("Extension"));
x.AddAllTypesOf<PluginBase>();
});
The difficulty I am then having is how to work against the interface (not the PluginBase) in code. It's easy enough to work with PluginBase:
var plugins = ObjectFactory.GetAllInstances<PluginBase>();
foreach (var plugin in plugins)
{
}
But specific functionality (e.g. IStartUpTask.RunTask) is tied to the interface, not the base class.
I appreciate this may not be specific to structuremap (perhaps more a question of reflection).
Thanks,
Ben
Do you know all of the specific interfaces at registration time? If so, you can make a custom registration convention that registers each type with the plugin "family" of the interface it implements. An IRegistrationConvention gets each type, one at a time. You could do a simple check to see if the current type implements the desired interface, and if so, add it.
if (typeof(IStartUpTask).IsAssignableFrom(currentType)){
For<IStartUpTask>().Add(currentType);
}
Then later in the code, you can retrieve plugins for each specific interface individually:
var startupTasks = ObjectFactory.GetAllInstances<IStartUpTask>();
This approach has the benefit of allowing you to inject an enumerable of your custom interface plugins into a class that needs them, instead of making the service location call.
Alternatively, if you don't want to make a registration convention, you can just do the filtering at runtime using the handy OfType linq extension method:
var startupTasks = ObjectFactory.GetAllInstances<PluginBase>().OfType<IStartupTask>();
In case it helps others, I followed Joshua's advice and added my own registration convention:
public class PluginConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry) {
if (type.BaseType == null) return;
if (type.BaseType.Equals(typeof(PSAdmin.Core.Domain.PluginBase))) {
if (typeof(IStartUpTask).IsAssignableFrom(type)) {
registry.For<IStartUpTask>()
.TheDefault.Is.OfConcreteType(type);
}
}
}
}
I couldn't get the .Add method to work, no matter what I tried, so had to use TheDefault.Is.OfConcreteType(type).
Then in my bootstrapper I am scanning like so:
Scan(x => {
x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"),
assembly => assembly.GetName().Name.Contains("Extension"));
x.Convention<PluginConvention>();
});
I can then grab my IStartUp task types like so:
var plugins = ObjectFactory.GetAllInstances<IStartUpTask>();
foreach (var plugin in plugins)
{
plugin.Configure();
}
That said, after reading up on some of the new features of StructureMap, I'm not sure I need to do any of the above. For example I could just change my Scan delegate function to:
Scan(x => {
x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"),
assembly => assembly.GetName().Name.Contains("Extension"));
x.AddAllTypesOf<PluginBase>();
});
And to use my interface concrete types (that inherit from PluginBase):
var tasks = ObjectFactory.Model.GetAllPossible<IStartUpTask>();
foreach (var task in tasks)
{
task.Configure();
}
Both methods seem to achieve the same thing.

Resources