How to register my service as a global service or

2019-09-10 03:18发布

问题:

I would like to create my own service with global visibility. To implement that, I followed this sample solution.

Everything goes well, I can call my service within a class, which extends from the Package abstract class, in this way:

public class ClientPackage : Package
{
   private void GetGlobalServiceCallback(object sender, EventArgs args)
   {
      IMyGlobalService service = GetService(typeof(SMyGlobalService)) as IMyGlobalService;
   }
}

Because I'm in a Package, I can easily call GetService and I can get my service. But what about if I want to get my service from a class, which is not extends the Package abstract class?

For example, I have a class, which implements an ITagger interface. If I want to get a service in this class, I have to use Package.GetGlobalService() method in this way:

var txtMgr = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager));

I tried to get my own service with the Package.GetGlobalServie(), but I always getting null. The linked sample code doesn't contain a soluiton for my problem.

May I missed something or I have a wrong scenario to get my service?

EDIT:

Okay, let's say I have to use MEF to get my service, because I can't get my service with Package.GetGlobalService().

I have a solution with 2 projects in it. One is a class library, which contains an interface like this:

public interface INamesAccessor
{
    IEnumerable<string> GetNames();
}

The other project is the VSPackage (has a reference with the first project), which implements my interface as well:

[Export(typeof(INamesAccessor))]
public sealed class BitbucketExtensionPackage : Package, INamesAccessor
{
    private IEnumerable<string> _names { get; set; }

    public IEnumerable<string> GetNames()
    {
        return _names;
    }
}

Let's say that if the user clicks a given menu under the Tools menu, the logic set the value of the names. Until that the _names is empty.

I would like to use the content of this _names list at my provider, like:

[Export(typeof(ITaggerProvider))]
[ContentType("text")]
[TagType(typeof(CommentTag))]
internal sealed class CommentTaggerProvider : ITaggerProvider
{
    [Import]
    public INamesAccessor _namesAccessor { get; set; }

    public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
    {
        if (buffer == null)
            throw new ArgumentNullException("buffer");

        return buffer.Properties.GetOrCreateSingletonProperty(() => new CommentTagger(buffer, _namesAccessor )) as ITagger<T>;
    }
}

I get the namesAccessor here, but every fields are null, the _names IEnumerable also.

Is there a way to force the MEF to import my accessor again when the user click to the menu button? What did I wrong?

Thank you for your answer! :)

回答1:

You should use MEF to composes services for your extensions; not the old COM-based ServiceProvider stuff.

Put all of your actual code in MEF-exported classes, then invoke them from the package class using the SComponentModel service.

For more information, see my blog.