This project is read-only.

Download - 417.8 KB


OSGi.NET helps .NET developers to reform and build software systems consisting of individual logical physical modules which are communicating with each others by Service Bus (a combination of pre-defined service interfaces, could add/get/remove specified service instance) or by extension point/extension (a mechanism that allow one module to publish extra infomations (extension, xml format) to another who subscribes the same topic (same extension ponit name) in oder to extend the subscriber dynamically. Modules (always called "Bundle") are under the control of OSGi.NET Runtime with life-cycle management (Installed, Resolved, Starting, Active, Stopping, Uninstalled) which is accessble by others when want to start it, or stop it later. All configuration is simply put in a readable, editable and reconfigurable file, Manifest.xml. Almost supports all types of .NET applications, even MVC (starts from MVC 3). Minimum supporting .NET version is 2.0.


"The key reason OSGi technology is so successful is that it provides a very mature component system that actually works in a surprising number of environments. The OSGi component system is actually used to build highly complex applications like IDEs (Eclipse), application servers (GlassFish, IBM Websphere, Oracle/BEA Weblogic, Jonas, JBoss), application frameworks (Spring, Guice), industrial automation, residential gateways, phones, and so much more. " --Benefits of Using OSGi

OSGi.NET, a dynamic modularization framework, which is a .NET implementation tightly based on OSGi specifications from OSGi Alliance, is designed and developed by Xi’an UI Information Technology, Inc., in China, from 2008.

Using the code

What's a Manifest.xml for? 

Every Bundle has a Manifest.xml to self-describe as a "Plugin" to OSGi.NET runtime environment, which more or less contains several parts as below:

  1. What's the Bundle's basic description, what's his name, what's the version, wht's the order to start? 
  2. Where are the assemblies should be loaded? Does it depend on any other Bundles or any Shared aseemblies form other Bundles? 
  3. Optionally: Where is Bundle entry point and exit point when it's started or stopped? 
  4. Optionally: Define a Service which can be called by other Bundles with an interface and one of its public sub-class that inherits it 
  5. Optionally: Define an Extension Ponit to subscribe a topic that's specified by Point attribute. Well, coming in pairs, define an Extension in other Bundles with same Point attribute to publish extra xml-formatted message
  6. Optionally: Details information of this Bundle about its author, company, category or copyright, etc. if has any

The following example describes the implementation of 3 Bundles ("OSGi.NET.MP3DecoderPlugin", "OSGi.NET.APEDecoderPlugin" and "OSGi.NET.AudioFormatService") or 2 types ( 2 Plugins and 1 Service) which work together with a Host ("OSGi.NET.AudioPlayerShell") to simulate a very simple Audio Player, just outputs the supported media types for choosing and its running status. Smile | <img src=  


Let's start with OSGi.NET.MP3DecoderPlugin, check out its Manifest.xml

<?xml version="1.0" encoding="utf-8" ?>
<Bundle xmlns="urn:uiosp-bundle-manifest-2.0" SymbolicName="OSGi.NET.MP3DecoderPlugin" Name="OSGi.NET.MP3DecoderPlugin" Version="" InitializedState="Active">
  <Activator Type="OSGi.NET.MP3DecoderPlugin.Activator"/>
    <Assembly Path="bin\OSGi.NET.MP3DecoderPlugin.dll"/>
  <Extension Point="OSGi.NET.AudioFormat">
    <AudioFormat Type="MP3" DecorderClass="OSGi.NET.MP3DecoderPlugin.Decoder" />
  • "SymbolicName" is the inner name for indexing and it must be unique
  • "InitializedState" indicates the first state after it's loaded, another option is "Installed" that meas will be "Avtive" later by manual if needed 
  • "Activator" with Type specified indicates the start and stop ponit of this Bundle before it's being "Active" or "Stopping", here we do nothing  
    public class Activator : IBundleActivator
        public void Start(IBundleContext context)
            //todo anything before Bundle is Active, like init a database connection
        public void Stop(IBundleContext context)
            //todo anything before Bundle is Stopping, like close a datbase connection
  • "Runtime" with Path specified indicates asembly that's ready for loading
  • "Extension" with Point specified indicates this Bundle will Publish the inner XML, that carrys the message what type this Bundle will support and by which decoder class, to Runtime that's ready for Subscribing with this topic by another Bundle. The decoder class is defiened below 
    public class Decoder : IAudioDecoder
        public void Decode()
            Console.WriteLine("MP3 decoder is decoding...");

OSGi.NET.APEDecoderPlugin does the same things so we continue to Service


This is the Manifest.xml of OSGi.NET.AudioFormatService

<?xml version="1.0" encoding="utf-8"?>
<Bundle xmlns="urn:uiosp-bundle-manifest-2.0" Name="OSGi.NET.AudioFormatService" SymbolicName="OSGi.NET.AudioFormatService" Version="" StartLevel="2" InitializedState="Active">
  <Activator Type="OSGi.NET.AudioFormatService.Activator" />
    <Assembly Path="bin\OSGi.NET.AudioFormatService.dll" Share="true" />
  <ExtensionPoint Point="OSGi.NET.AudioFormat" />
  • "StartLevel" indicates the starting order of this Bundle, the less means start earlier, minimum is 2, default is 50. Start the Service before any others in order to comsume when it's ready  
  • Another difference between plugin above is "ExtensionPoint" with Point specified that indicates this Bundle will subscrtibe all Extension information of this Point. This definition is not necessary, we can handler the Extention in code with/without it
  • This is a Service Bundle but there is no definition about any Service, same reason, we can handler it in code, too 
  • That's the way we do here, read the comments for details  
    public void Start(IBundleContext context)
        //Add a IAudioFormatExtensionService instance to Service Bus
        //AudioFormatExtensionService is inherits IAudioFormatExtensionService
        context.AddService<IAudioFormatExtensionService>(new AudioFormatExtensionService());
        //Handler the extension if it's changed in run-time dynamically
        context.ExtensionChanged += context_ExtensionChanged;
        //Get the specified extension by Ponit
        List<Extension> extensionList = context.GetExtensions("OSGi.NET.AudioFormat");
        if (extensionList != null && extensionList.Count > 0)
            foreach (Extension extension in extensionList)
                //deal with each extension in AudioFormatExtensionContainer at run-time start
    void context_ExtensionChanged(object sender, ExtensionEventArgs e)
        if (e.ExtensionPoint == "OSGi.NET.AudioFormat")
            if (e.Action == CollectionChangedAction.Remove)
                //remove the extension if the owner bundle is removed in run-time dynamically
            else if (e.Action == CollectionChangedAction.Add)
                //add the extension if the owner bunlder is added in run-time dynamically
  • Here the definiation of IAudioFormatExtensionService 
    public interface IAudioFormatExtensionService
        List<string> GetAllAudioFormatTypes();
        IAudioDecoder GetAudioDecoderByType(string type);
  • Here is AudioFormatExtensionService 
    public class AudioFormatExtensionService : IAudioFormatExtensionService
        public List<string> GetAllAudioFormatTypes()
            List<string> types = new List<string>();
                extension => types.Add(extension.Type));
            return types;
        public IAudioDecoder GetAudioDecoderByType(string type)
            AudioFormatExtension audioFormatExtension = AudioFormatExtensionContainer.Intance.AudioFormatExtensionList.Find(
                extension => extension.Type == type);
            if (audioFormatExtension != null)
                return audioFormatExtension.Decoder;
                return null;


Host will get all supporting media types var Service above, here is the code with comments 

static void Main(string[] args)
    //Create BundleRuntime context, inherits IDisposable
    using (BundleRuntime bundleRuntime = new BundleRuntime())
        //Start BundleRuntime
        while (true)
            //Get first or default IAudioFormatExtensionService service from Service Bus
            IAudioFormatExtensionService audioFormatExtensionService = bundleRuntime.GetFirstOrDefaultService<IAudioFormatExtensionService>();
            if (audioFormatExtensionService != null)
                Console.WriteLine("Please select the audio type:");
                //loop all types and output
                audioFormatExtensionService.GetAllAudioFormatTypes().ForEach(type => Console.WriteLine(type));
                string selectedType = Console.ReadLine();
                Console.WriteLine(string.Format("your selection is {0}", selectedType));
                //Get IAudioDecoder by its Type
                IAudioDecoder decoder = audioFormatExtensionService.GetAudioDecoderByType(selectedType);
                if (decoder != null)



More Fun

With the Remote Console Tool, we can do a litte fun here with host running

  • The init screenshot
  • Input "list" or "l"
  • Input "stop 4" or "sp 4" (4 is the Id of Bundle OSGi.NET.MP3DecoderPlugin in runtime)

    The press key "Enter" in Host application, the MP3 option is gone
  • Input "start 4" or "s 4"

    The MP3 will be back
  • Stop the Host, and zip the OSGi.NET.MP3DecoderPlugin folder before delete it, that means OSGi.NET.MP3DecoderPlugin will be out of this application.
  • Here let's demo how to install a Plugin remotely. Asume the path of zip file is "D:\". 
    Start Host application, there is no MP3 option

    Then in Remote Console Tool, input: i "OSGi.NET.MP3DecoderPlugin" "D:\" "D:\\OSGi.NET\Demo1\OSGi.NET.AudioPlayerShell\OSGi.NET.AudioPlayerShell\bin\plugins\FormatTypes\Lossy\OSGi.NET.MP3DecoderPlugin"

    Show the list and start it

    Press Enter in Host, MP3 is back then

Points of Interest

Let’s brief how this happens:

  1. Host starts the BundleRuntime
  2. then runtime search all Manifest.xml files under a specified path, here it’s “bin\Plugins”of Host itself
  3. from Manifest, runtime gets where assembly should be load and where the entry ponit Start() in Activator is
  4. at last, run the Start()
  5. Also, in Start() Bundle registries Service and Handles Extention from Manifest.xml
  6. Host comsumes the Service var BundleRuntime, that's all 

Interesting thing are:

  • Host never know whether there are some Plugins or not, but eventually BundleRuntime will load them all or none
  • Plugins never konw wheter there is a Host or not, but eventually it will be loaded by BundleRuntime if there is one 
  • Every single Plugin is in a single Folder, you can add it or remove it from “bin\Plugins”,  we don’t need re-build Host or other Plugins but they could work together without any problems 

Last edited Mar 25, 2013 at 4:10 PM by shalahu, version 2


shalahu Jun 6, 2014 at 8:30 AM 
Make sure you have the right Manifest.xml configuration, then chck out the log.txt at bin folder to find more details.

gangzizhang Apr 25, 2014 at 6:20 AM 
It failed when i install a web plugin by Remote Console Tool.
The plugin can't display in the Plugin list, could you tell me the possible reasons?
Thanks a lot!