Dependency Injection C# Visual Studio For Mac

Active3 years, 7 months ago
  1. Visual C++ For Mac
  2. C# Dependency Injection Frameworks
  3. Visual Studio On A Mac

I'm working on a visual studio add-in that takes SQL queries in your project, plays the request and generates a C# wrapper class for the results. I want to do a simplest possible dependency injection, where projects using my add-in supply a class that can provide the project's db connection string, among other things.

Visual C++ For Mac

I'm planning to do a talk on Dependency Injection and IoC Containers, and I'm looking for some good arguments for using it. What are the most important benefits of using this technique, and these. Dependency Injection mainly reduces the tight coupling between the classes. Dependency Injection moves the abstraction binding out of the class or higher level modules. By Dependency Injection, we can achieve the process of removing the dependency of low level modules from higher level modules. Software Architecture: Dependency Injection for C# Devs 4.2 (130 ratings) Course Ratings are calculated from individual students’ ratings and a variety of other signals, like age of rating and reliability, to ensure that they reflect course quality fairly and accurately.

This interface is defined in my add-in...

And the question : How do I define and instantiate the concrete implementation, then use it from the add-in?

Progress?

The interface above is defined in the add-in. I've created a reference in the target project to the add-in, written the concrete implementation, and put the name of this class in the target project web.config. Now I need to load the target project from the add-in to use my concrete class.

If I use Assembly.Load()...

I can successfully load my class, but I lock the target assembly and can no longer compile the target project.

C# Dependency Injection Frameworks

If I create a temporary app domain...

I get a file not found exception on the call ad.Load(), even though the bytes of my dll are in memory.

If I use CreateInstanceFromAndUnwrap()...

Visual studio on a mac

I get an

InvalidCastException. 'Unable to cast transparent proxy to type QueryFirst.IQueryFirst_TargetProject'

This makes me think I'm very close? Why would an explicit cast work fine with Assembly.Load(), but fail when the same assembly is loaded in a newly created AppDomain?

Community
bbsimonbbbbsimonbb
12.6k6 gold badges40 silver badges56 bronze badges

1 Answer

I'm assuming that your add-in is going to be triggered in someway in order to start working with SQL Queries.

I'd recommend that you bundle a separate .exe file with your add-in and do the processing in there.

Here's why:

  1. Personally, I've had a lot of issues with AppDomains similar to what you're running into with file locking and the head ache of Temp Domains. The other issue you'd likely run into is once you load an Assembly into an AppDomain, you can't unload. By using a separate process (that dies when it's finished) you don't have to worry about the problem.
  2. Depending on the type of Projects you want to support, those Projects will have dependencies. Managing references to dependent dlls will be a lot easier if you can just point your standalone .exe at a directory (ie the bin directory).
  3. If you hook into Visual Studio's Build Events (DTE.Events.BuildEvents.OnBuildBegin) you can kill your process and release the locks on the dll files. Or you could have your process first make copies.
  4. Testing/debugging is a lot easier with a stand alone file. You don't need to worry about trying to debug by attaching to Visual Studio (How to debug a Vsix project).

You can use the following methods to start/kill processes:

I think you can reference the output of a Console Project directly from your VSIX Add In Project via the References Anatomy of a VSIX Package. Otherewise, you might need to do some custom MSBuild to get the .exe included within the VSIX file.

Once it's included, you can find the .exe because it should be in the same path as your executing VSIX (Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) and I would pass it the Path to the loaded Project's bin directory.

As an aside, this isn't Dependency Injection. If you want to use DI inside a VS Extension, you can use whatever framework you'd like, but I think MEF is natively supported. Personally, I prefer Ninject. Define your Kernel inside the Package class and the use it to load your top level class.

Community
Philip PittlePhilip Pittle
7,0746 gold badges38 silver badges91 bronze badges
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.

Not the answer you're looking for? Browse other questions tagged c#visual-studiovisual-studio-addins or ask your own question.

A Portable Class Library (PCL) allows you to target the platforms you wish to support, and use Interfaces to provide platform-specific functionality. This is also known as dependency injection. You will often run into limitations with PCLs with UI-related needs which require specialized handling on each platform. In my example I will be using the Xamarin.Mac and .NET Framework 4.5 Frameworks. Other frameworks such as Windows 8, Xamarin.Android and Xamarin.iOS will automatically be included. This is a desktop app that runs on Windows and OSX, and shares code with a PCL.

Creating the Solution and Projects

I began by creating a new project in Visual Studio. Search for Portable. I chose Class Library (Portable) under C#. I did not choose the Class Library (Xamarin.Forms Portable) because I am not referencing that library in my non-mobile application. Name it Portable, select your frameworks and create.

Next, I renamed my solution to Proj. I just wanted to distinguish it from my different projects. All your files are stored in a root folder named Portable. This can be renamed later to match the solution name if desired. I then right-clicked on my solution to add a new project. I chose WPF Application and named it Win. I set it as my startup project. On my OSX Laptop I also opened the same solution in Xamarin Studio. It showed the Win project as unsupported and that’s fine. On the solution I went to Add New Project. Under Mac App I chose a General Empty Project. I named it Mac. Once complete set it as the Startup Project. Back in Windows I reopened my solution it gave me an Unsupported notice and migration report about the Mac project. Disregard.

PCL Code

Now let’s write some code. In my example I am going to retrieve Machine Information. In my experience I have struggled to find a PCL nuget that could fetch detailed platform machine information. Under my Portable I added a new class called IPlatform. Inside it I created an interface:
2
4
{
}
Next, I created an PlatformManager class with the following code:
2
4
6
8
10
12
{
publicPlatformManager(IPlatform platform)
_platform=platform;
publicDictionary<string,object>GetMachineInfo()
returnthis._platform.GetMachineInfo();
}
Next, I added a third class to the portable. I named it StaticUtils
2
4
6
8
10
12
14
{
publicstaticvoidAssignPlatformManager(IPlatform platform){
}
{
{
}
}

Windows Project Code

Now we need to create the proper hooks in our Win project. In my app.xaml.cs file I added the following:
2
4
6
8
privatevoidApplication_Startup(objectsender,StartupEventArgse)
//implement the interface
Portable.IPlatform implementedInterface=newWinInterface();
//pass in the interface to create a static PlatformManager object to be referenced
Portable.StaticUtils.AssignPlatformManager(implementedInterface);
Next, I added a class called WinInterface I added this code:
2
4
6
8
10
12
14
16
18
20
22
24
{
{
varprocessorCnt=Environment.ProcessorCount;
varosName='Windows';
varci=newMicrosoft.VisualBasic.Devices.ComputerInfo();
varappVersion=FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;
dict['Is64Bit']=is64Bit;
dict['MachineName']=machineName;
dict['OSVersion']=osVersion;
dict['AppVersion']=appVersion;
}

Mac Project Code

In my AppDelegate.cs file I added the following:
2
4
{
Portable.IPlatform implementedInterface=newMacInterface();
Portable.StaticUtils.AssignPlatformManager(implementedInterface);
Next, I added a class called MacInterface I added this code:
2
4
6
8
10
12
14
16
18
20
22
{
{
varprocessorCnt=Environment.ProcessorCount;
varosVersion=Foundation.NSProcessInfo.ProcessInfo.OperatingSystemVersionString;
varram=Foundation.NSProcessInfo.ProcessInfo.PhysicalMemory;
varappVersion=Foundation.NSBundle.MainBundle.ObjectForInfoDictionary('CFBundleShortVersionString').ToString();
dict['Is64Bit']=is64Bit;
dict['MachineName']=machineName;
dict['OSVersion']=osVersion;
dict['AppVersion']=appVersion;
}

How It All Works

The platform project starts and instantiates their class of methods implementing the portable interface. We then call an assignment method in the portable’s StaticUtils class. The assignment method instantiates a new, static PlatformManager for us to reference, and the manager stores the passed interface into a variable within itself. With a static reference we can access it through the life on the application. Now, when we want to fetch our platform method details we reference the static PlatformManager, which references the interface that implements the platform-specific code. Calling it like so will return the desired data:
varinfo=StaticUtils.PlatformManager.GetMachineInfo();

Visual Studio On A Mac

Download a working example developed in Visual Studio 2013.