Click here to Skip to main content
15,882,838 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to learn dependency injection.

Ive made a test app to try it out. The output should be "Testing Appended string", but it keeps giving me a NullReferenceException. Any help?
C#
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Reflection;
using System.Text;
using System.ComponentModel.Composition;

namespace buildtest
{
    interface IAppend
    {
        string Append(string str);
    }

    [Export(typeof(IAppend))]
    class Appender : IAppend
    {

        public string Append(string str)
        {
            return str + "Appended string";
        }
    }

    class AppHelper
    {
        [Import(typeof(IAppend))]
        public IAppend App { get; set; }

    }

    class runner
    {
        public void Run()
        {
            AppHelper t = new AppHelper();
            //Composition
            CompositionContainer container;
            try
            {
                var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
                container = new CompositionContainer(catalog);
                container.ComposeParts(this);

            }
            catch (Exception ex)
            {
                throw ex;
            }
            t.App.Append("Testing ");

            Console.ReadLine();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {

            new runner().Run();
        }
    }
}
Posted
Comments
Sergey Alexandrovich Kryukov 2-Apr-14 16:00pm    
In what line?
—SA

C#
container.ComposeParts(this);

With this line you try to put the composable parts into this!!!
C#
container.ComposeParts(t);

And now you put it into your new AppHelper!!!

[As advised by SA more explanation why that works]
MEF is a plugin engine that can load classes from different assemblies, create instances from the classes in the loaded assembly and assign that object to some property in the hosting assembly.
The pairs are made according the Export/Import attributes.
For instance in our code we have an external (almost) class signed with Export[IAppend] and we have a class - AppHelper - that has property signed with Import[IAppend].
When calling the MEF engine via ComposeParts, the engine looks for such pairs and make the connection. If we pass some object that has no properties with the matching sign (like this) MEF engine will return without any action. However if we pass an object - like t - to the engine it will assign an instance of the external class to the matching property - in our case App.
 
Share this answer
 
v3
Comments
stubobis1 2-Apr-14 16:29pm    
Thank you SO MUCH!

Can you explain why it works like that?
Kornfeld Eliyahu Peter 2-Apr-14 16:37pm    
The heart of MEF is pair Export to Import. this (your runner class) was not signed as an Import point, so MEF couldn't add the composable parts to it. But t - which of type of AppHelper - is signed with the proper Import...
You have to read more about how MEF is build to understand the Export-Import schema.
(I have to little article that talk about implementations using MEF. After you did some basic reading you may be interested in them
http://www.codeproject.com/Tips/622400/Windows-Service-to-Host-Multiple-WCF-Services
http://www.codeproject.com/Articles/668153/Extensible-Web-Application)
stubobis1 2-Apr-14 16:56pm    
Again, Thank you!
Maciej Los 2-Apr-14 16:47pm    
Hawk eye!
+5!
Kornfeld Eliyahu Peter 2-Apr-14 16:51pm    
Oh, not really, but I worked with MEF over the last year very intensively...
You did not show where the exception with the message "Object reference not set to an instance of an object" is thrown.

Not to worry. This is one of the very easiest cases to detect and fix. It simply means that some member/variable of some reference type is dereferenced by using and of its instance (non-static) members, which requires this member/variable to be non-null, but in fact it appears to be null. Simply execute it under debugger, it will stop the execution where the exception is thrown. Put a break point on that line, restart the application and come to this point again. Evaluate all references involved in next line and see which one is null while it needs to be not null. After you figure this out, fix the code: either make sure the member/variable is properly initialized to a non-null reference, or check it for null and, in case of null, do something else.

Please see also: want to display next record on button click. but got an error in if condition of next record function "object reference not set to an instance of an object"[^].

Sometimes, you cannot do it under debugger, by one or another reason. One really nasty case is when the problem is only manifested if software is built when debug information is not available. In this case, you have to use the harder way. First, you need to make sure that you never block propagation of exceptions by handling them silently (this is a crime of developers against themselves, yet very usual). The you need to catch absolutely all exceptions on the very top stack frame of each thread. You can do it if you handle the exceptions of the type System.Exception. In the handler, you need to log all the exception information, especially the System.Exception.StackTrace:
http://msdn.microsoft.com/en-us/library/system.exception.aspx[^],
http://msdn.microsoft.com/en-us/library/system.exception.stacktrace.aspx[^].

The stack trace is just a string showing the full path of exception propagation from the throw statement to the handler. By reading it, you can always find ends. For logging, it's the best (in most cases) to use the class System.Diagnostics.EventLog:
http://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog.aspx[^].

[EDIT]

After OP's clarification (thank you, stubobis1!):

The immediate problem is now obvious. In the line you pointed out, t.App is null. In the same line, you try to dereference the result of calculation of t.App (which is the property getter call) by calling Append(string) on the null value, which result in the exception you complained about.

Now, why t.App is null? Because you never assigned it a value. Solution 1 explains what you could have done.

Good luck,
—SA
 
Share this answer
 
v4
Comments
Kornfeld Eliyahu Peter 2-Apr-14 16:13pm    
It's much simpler, see my answer...
Sergey Alexandrovich Kryukov 2-Apr-14 16:18pm    
Maybe you answer is correct, but I cannot agree that the answer should be "simpler" than mine. It's simple enough. OP needs to be able to figure out things by himself, instead of getting a concrete easy-to-use fix you offered. Next time, you may be asked the same question from the same inquirer. Do you call it help? I think saying "go ahead and use the debugger" would be even more useful.
—SA
Kornfeld Eliyahu Peter 2-Apr-14 16:24pm    
Oh, I didn't mean by that, that what you are saying is wrong or useless, not at all - you are correct about that OP (or any other programmer) have to develop his abilities to a certain level. My thought was, that it is only a typo, as OP's code nothing more than the most basic MEF sample...
stubobis1 2-Apr-14 16:28pm    
I forgot to say where the null ref was being thrown;
it was thrown @ t.App.Append, when it tried to access the app though AppHelper.
Sergey Alexandrovich Kryukov 2-Apr-14 17:41pm    
Well, thank you, it helped me to complete the fix for you; please see the update to my answer, after [EDIT].
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900