What are the best practices to create a site, with ability to develop plugins for it?
Like you want to create a blog module, and you want users or co-developers to add plugins to extend this module functionality.
Update:
Thanks for the ultra speed answers, but I think this is over kill for me. Isn't there a simpler solution, like I have seen blogengine plugin creation system is you just have to decorate the class plugin with [Extension].
I am kind of mid core developer, so I was thinking of base class, inheritance, interfaces, what do you think ?
Edit
I completely rewrote my answer based on your question edit.
Let me show you just how easy it is to implement a plugin architecture with just the minimal steps.
Step 1: Define an interface that your plugins will implement.
namespace PluginInterface
{
public interface IPlugin
{
string Name { get; }
string Run(string input);
}
}
Step 2: Create a plugin that implements IPlugin.
namespace PluginX
{
using PluginInterface;
public class Plugin : IPlugin
{
public string Name
{
get { return "Plugin X"; }
}
public string Run(string input)
{
return input;
}
}
}
Step 3: Run the plugin.
namespace PluginTest
{
using System;
using System.IO;
using System.Runtime.Remoting;
using PluginInterface;
class Program
{
static void Main( string[] args )
{
string pluginFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PluginX.dll");
ObjectHandle handle = Activator.CreateInstanceFrom(pluginFile, "PluginX.Plugin");
IPlugin plugin = handle.Unwrap() as IPlugin;
string pluginName = plugin.Name;
string pluginResult = plugin.Run("test string");
}
}
}
Keep in mind, this is just the basic, most straightforward example of a plugin architechure. You can also do things such as
create a plugin host to run your plugin inside of it's own AppDomain
choose either interfaces, abstract classes, or attributes to decorate your plugins with
use reflection, interfaces, IL-emitted thunks or delegates to get the late binding job done
if your design so dictates.
It's valuable to separate technical and architecturas perspectives:
In code level MEF (Managed Extensibility Framework) is a good start. Here is a simple example.
Any other DI (Dependency Injection framework) can work well to (ie. Unity)
And it's good to see this problem in architectural level:
Web Client Software Factory from p&p. Here are not only technical but arcihtectural informations about "How to create composite web applications?". See examples.. There is Modularity Boundle package.
Spring Framework.
I think it's a fast and efficient if you read&try some of those frameworks. And ofcoz read the source if you find something interessing.
Edit
if you are searching for an extensible blog engine then try Blog Engine first. It's from ASP.NET community.
This sounds like a job for the Managed Extensibility Framework from Microsoft. It's in a preview release at the moment but it would seem to be a better bet than rolling your own framework for this. There are links to guides about how to use this on the site there.
If you would like to see a real, open source application that impliments this archecture take a look at DotNetNuke.
Related
I want to add a custom test reporter to NUnit. I already did it with NUnit2, but I now need to use NUnit3.
To implement the reporter, I need to get various events from the framework, like start, end and failure of tests.
In NUnit2 I used NUnitHook to register my EventListener and it worked pretty good.
In NUnit3 I need to use the extension point mechanism, but when I add the extension point to the project, VisualStudio (2012 ultimate) immediately fails to discover the NUnit tests.
[TypeExtensionPoint(Description = "Test Reporter Extension")]
public class MyTestEventListener : ITestEventListener
{
public void OnTestEvent(string report)
{
Console.WriteLine(report);
}
}
If I remove the ITestEventListener implementation declaration from the class, it rediscovers the tests perfectly.
[TypeExtensionPoint(Description = "Test Reporter Extension")]
public class MyTestEventListener //: ITestEventListener
{
public void OnTestEvent(string report)
{
Console.WriteLine(report);
}
}
Am I doing something wrong? is there a better way to achieve it?
You don't say where you are putting this code, but I am suspecting it's in your test assembly. If so, that's not where it belongs. NUnit engine extensions get installed into the NUnit engine, so they need to be in a separate assembly. Once you have a separate assembly, you need to tell the engine where it is. Currently, you do this by creating a file of type .addins in the same directory as the engine. (You could modify the existing file, but that introduces maintenance problems in the future)
A future release will have an easier way to install addins, but they will continue to be entirely separate from your tests.
A further problem is that you are using TypeExtensionPointAttribute. I didn't notice this originally in your code and it's probably the biggest error so I'm adding this info now.
An "ExtensionPoint" is the thing you are extending. NUnit defines ExtensionPoints, while you create Extenisons to extend them. TypeExtensionPointAttribute is used inside NUnit to define extension points. It's not used by you. You use the ExtensionAttribute to define your extension.
Your extension should be defined something like this:
[Extension(Description = "Test Reporter Extension", EngineVersion="3.4")]
public class MyTestEventListener : ITestEventListener
{
public void OnTestEvent(string report)
{
Console.WriteLine(report);
}
}
You don't say what version of NUnit you are running. Test Listeners are only supported beginning with version 3.4. The EngineVersion property above is purely documentary at this point, because 3.4 is also the first version to recognize it.
There is a new writeup in the NUnit docs that may be helpful: https://github.com/nunit/docs/wiki/Writing-Engine-Extensions
I’m at the moment automating the test for a legacy application developed in vb6, which uses a GridEx2000b Control from Janus Systems.
For doing this I’m using Ranorex as my favorite tool for developing the test automation, so that I can develop the test code using c#.
My problem now is to automate the GridEx 2000b control, which Ranorex out of-the-box don’t have any support for. Therefore I’m trying to figure out a solution where I can reference the GrixEx control using the Win32 handle I can find for the control, so I can use the ComInterface from the component to navigate the automate the control.
I have an idea of a solution but I cannot figure out how to do it, where I hope that you guys would be able help me.
The pseudo code for the problem:
using GridEX20;
class GridExWrapper
{
public GridEX20.GridEXClass Instance;
public GridExWrapper(IntPtr win32handle)
{
Instance = (GridEX20.GridEXClass)Win32ControlUtilities.GetControlReference(win32Handle);
}
}
class Win32ControlUtilities
{
public static SomeKindOfHandle GetControlReference(IntPtr win32Handle)
{
...
...
...
}
}
I’ll get the win32handle from Ranorex or some other spy tool.
Then I can use the GridExWrapper like this.
using NUnit.Framework;
class Program
{
[Test]
public void control_should_have_9_items()
{
/// Get win32 handle from Ranorex
IntPtr win32handle = XXXXXX;
int expectedItemCount = 9;
GridEXClass control = new GridExWrapper(win32handle);
Assert.AreEqual(expectedItemCount, control.ItemCount);
}
}
You could try the Microsoft UI Automation library (System.Windows.Automation) for identifying the properties of the control. Sometimes even if Ranorex fails, MSUIA manages to recognize the control as it looks into native properties of a control for identification. Not guaranteed but worth a try.Here is a link to a tutorial on using MSUIA.
I've been following a set of tutorials (like this one) to create a simple COM server object.
Say I've got a simple hello world:
[ComVisible(true)]
[Guid("392930B3-9CD0-4247-8C69-83168D1C8F77")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("nathanr.HellowWorldCom")]
class HelloWorldCom : IHelloWorldCom
{
public int HelloWorld()
{
Console.WriteLine("Hello World!");
return 1;
}
}
With just as simple an interface:
[ComVisible(true)]
[Guid("C08205BE-1393-4070-AE57-FA47F0D653C3")]
interface IHelloWorldCom
{
[DispId(1)]
int HelloWorld();
}
And of course, can't forget the AssemblyInfo.cs file:
...
[assembly: ComVisible(true)]
[assembly: AssemblyKeyFile("HelloWorldCOM.snk")]
...
The problem is when I build the HelloWorldCom.dll and try to register it, regasm just sticks its tongue out at me:
RegAsm : warning RA00000 : No types were registered.
And just to cover my bases I cracked open Regedit and did a search for the ProgID. It wasn't there, which honestly wasn't a surprise.
Am I missing something obvious?
This whole test project is part of a larger (actually useful) set up which is also failing to register.
This will be a very long answer: add public
public class HelloWorldCom : IHelloWorldCom
There might be couple of issues:
You are selecting an incorrect .net framework. In my case, I was trying to register the dll with 2.0 framework, as opposed to 64 bit 4.0 framework
Your DLL is not publicly exposed.
Hope that resolves your issue.
Cheers
The suggested way of using ServiceStack.NET with Silverlight is to use the Linked-Project addon. This enables two synchronous Projects and their sources, one for Silverlight, one for .NET 3.5+.
But when it comes to validation, this gets a bit annoying.
ServiceStack is using FluentValidation, which is cool. But it has changed the namespace.
So I end up with:
using MyNamespace.Model;
// HERE ----------------------------
#if SILVERLIGHT
using FluentValidation;
#else
using ServiceStack.FluentValidation;
#endif
//TO HERE------------------------
namespace HR.RoBP.Contracts.Validators.Model
{
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(r => r.Name).NotEmpty().NotNull();
}
}
}
This is not much, but it gets really annoing when writing a new validator each time. I often forget it, compile, have errors, fix it.
I know there is something changed in FluentValidation on ServiceStack.NET.
But must it be in a seperate Namespace?
I think its in the interest of servicestack to keep code files clean.
But using the the same validation on client and server forces me to do this.
If there is a elegant way to fix this issue, I would love to hear about it.
You unfortunately can't set a project-wide namespace alias. You could however try to write a template for your validator class that has that boilerplate code built in, and you can easily click Add -> New Item -> Your Validator Template.
I've an API DLL (API.dll, for example) which, in addition to many other thinks, makes available an abstract class (AbstractClass).
Now making use of that AbstractClass I've implemented it on two different dlls:
First.API.Implementation.dll with ConcreteImplementation1
Second.API.Implementation.dll with ConcreteImplementation2
Both ConcreteImplementation1 and ConcreteImplementation2 are implementation of the same abstract class.
What I want is an application where I can choose which of those two dlls to use and, through that, choose which implementation to use without the user having to change anything within the code and, if possible, without stopping the application.
Some configuration file where I can bring the application to use whatever implementation I want. Something like:
<appconfiguration>
<implementation_to_use>
<dll>First.API.Implementation.dll</dll>
<class>ConcreteImplementation1</class>
</implementation_to_use>
</appconfiguration>
I know near to nothing about dependency injection, apart from its concept, but I guess thats the perfect fit for this task.
I've researched several DI/IoC libraries but I'm not familiar with all the concepts and names. I can use whatever library I want. For what I can say these are the most used: StructureMap, Ninject and Sprint.NET
Moreover, apart from all the dlls and implementation I need to indicate a file to be used by that application. Can I indicate its path in that same file?
I just need some tips and directions to implement such a thing. Some examples using one of those libraries, would be awesome.
Thanks.
To get you started using StructureMap, create a console application, include in it:
structuremap.config:
<?xml version="1.0" encoding="utf-8" ?>
<StructureMap MementoStyle="Attribute">
<DefaultInstance
PluginType="DemoIoC.AbstractBase,DemoIoC"
PluggedType="DemoIoC.ConcreteImplementation1,DemoIoC"
Scope="Singleton" />
</StructureMap>
The PluginType and PluggedType attributes are "FullyQualifiedClassName,AssemblyName"
By default it will look for assemblies in the executable folder, I'm not sure how you would specify another location for the assemblies
There are plenty of options for Scope, e.g. Singleton, Transient, etc
Program.cs:
namespace DemoIoC
{
using System;
using StructureMap;
public static class Program
{
public static void Main(string[] args)
{
// here you initialize structuremap from the config file.
// You could probably use a FileSystemWatcher to reinitialize
// whenever the structuremap.config file changes
ObjectFactory.Initialize(x =>
{
x.UseDefaultStructureMapConfigFile = true;
});
var concrete = ObjectFactory.GetInstance<AbstractBase>();
concrete.Method1();
Console.ReadKey(true);
}
}
}
AbstractBase.cs:
namespace DemoIoC
{
public abstract class AbstractBase
{
public abstract void Method1();
}
}
ConcreteImplementation1.cs:
namespace DemoIoC
{
using System;
public class ConcreteImplementation1 : AbstractBase
{
public override void Method1()
{
Console.WriteLine("Called ConcreteImplementation1");
}
}
}