How to call VSTO class from other c# project - c#

In my solution I have 2 projects.
One is the controller, which in the final product is used to check if a execution is issued from console/non user input and therefore will execute the wanted changes in background based on imput from a xml-file, or if the execution was issued by user input, which will open an interface.
A non user input would maybe a planed task or something like that, but thats is for an other time now and I just write that for some context.
In both cases, sooner or later there is the need to access word-documents and read, write and change document-properties.
To do that I created a VSTO-Word-Addin with the needed functions and up to this point I hardcoded the paths and didn't return the results anywhere else than an other document.
Since I am sure my code in VSTO itself works, I wanted to extend the prototype to the next level and tried adding the connections between console and VSTO.
For testing I am simplifying the process a bit and just try to establish the connection between console and VSTO without any userinput and trying to execute some methods to test functionality of my VSTO.
My approach was to open the console, which then opens Word/the addin, open the file hidden and do the magic.
First thing to do is to set a path for the document to be opened and then call multiple methods with returned values.
In this case my VSTO returns a true for
SetCustomProperty
and a new List of Tuples for
GetCustomProperties
Those are placeholders and will be replaced in developement.
I already tried some possible solutions, but most of them go the other way around to start a WinForms/WPF/Console out of VSTO or try to call an other AddIn from their AddIn.
The approach I had the most success with was this one:
MSDN
Calling Code in VSTO Add-ins from Other Office Solutions
But of course this is for office so I hit the problem of not being able to use
Globals
More info about Globals can be found here in MSDN
So maybe I am missing the point and am just blind, but how can I call a class in a VSTO-project from console?
Here are some codesamples of my current failure:
The class with the used interface I want to access:
[ComVisible(true)]
public interface IPropertyReadWriter
{
bool Open(string Path);
bool SetCustomProperty(String Name, PropertyTypes Type, object Value);
List<Tuple<String, PropertyTypes, object>> GetCustomProperties();
}
[ComVisible(true)]
public class PropertyReaderWriter : IPropertyReadWriter
{
public List<Tuple<string, PropertyTypes, object>> GetCustomProperties()
{
return new List<Tuple<string, PropertyTypes, object>>();
}
public bool Open(string Path)
{
return false;
}
public bool SetCustomProperty(string Name, PropertyTypes Type, object Value)
{
return false;
}
}
The code used in the MSDN article about calling from other office-project:
object addInName = "ExcelImportData";
Office.COMAddIn addIn = Globals.ThisAddIn.Application.COMAddIns.Item(ref addInName);
ExcelImportData.IAddInUtilities utilities = (ExcelImportData.IAddInUtilities)addIn.Object;
utilities.ImportData();
I dont know how to make use of this, because I don't have access to Globals outsite of VSTO?
Somewhat similar question on so with no answer I could use, because lack of context or example:
I don't know what Dan Byström meant with his answer, also Mike Regan's answer lead to prior stated MSDN.
How to call a VSTO AddIn method from a separate C# project?

First, to your Addin that you want to call into add an Interface:
[ComVisible(true)]
public interface IExcelUtilities
{
bool DoSomething();
}
Next, add a class that implements the interface:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class AddInUtilities :
StandardOleMarshalObject,
IExcelUtilities
{
public bool DoSomething()
{
return true;
}
}
Then override object RequestComAddInAutomationService in ThisAddin.cs:
private AddInUtilities utilities;
protected override object RequestComAddInAutomationService()
{
try
{
if (utilities == null)
{
utilities = new AddInUtilities();
}
return utilities;
}
catch (System.Exception ex)
{
// Catch your ex here
}
}
Now you should be able to call the exposed method from your external application like this:
foreach (COMAddIn comaddin in addins)
{
if (comaddin.ProgId.Equals("YourAddinNameHere", StringComparison.InvariantCultureIgnoreCase) == true)
{
bool returnvalue = comaddin.Object.DoSomething();
break;
}
}
for some more deep info on this subject, also read:
http://blogs.msdn.com/b/andreww/archive/2008/08/11/why-your-comaddin-object-should-derive-from-standardolemarshalobject.aspx
Hope it helps :-)

This isn't an answer exactly, but for others coming across this, document-level solutions cannot expose interfaces to other solutions.
Expose an object in a VSTO Add-in to other Microsoft Office solutions.
VSTO Add-in projects. Call code in VSTO Add-ins from other Office solutions

Related

ICommandHandler not executing for SaveCommandArgs (Visual Studio for Mac Extension)

I'm trying to create simple extension for Visual Studio for Mac which will handle the moment when user saves the document (sample project is on GitHub, right here).
Here's how looks my implementation of ICommandHandler<SaveCommandArgs>:
[Export(typeof(ICommandHandler))]
[Name(nameof(SaveCommandHandler))]
[ContentType(StandardContentTypeNames.Code)]
[TextViewRole(PredefinedTextViewRoles.PrimaryDocument)]
public class SaveCommandHandler : ICommandHandler<SaveCommandArgs>
{
public string DisplayName => nameof(SaveCommandHandler);
private readonly IEditorCommandHandlerServiceFactory _editorCommandHandlerServiceFactory;
[ImportingConstructor]
public SaveCommandHandler(IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory)
{
_editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory;
}
public bool ExecuteCommand(SaveCommandArgs args, CommandExecutionContext executionContext)
{
try
{
var service = _editorCommandHandlerServiceFactory.GetService(args.TextView);
Debug.WriteLine($"I am executing something on save with {service.GetType()}");
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
return true;
}
public CommandState GetCommandState(SaveCommandArgs args)
{
return CommandState.Available;
}
}
Good point: system call the constructor of this handler, when you start editing the first file
Bad point: ExecuteCommand method never called, as well as GetCommandState method
Any ideas why it doesn't work?
I was trying to do all the things according to the documentation on official wiki in github project for visual studio api
Unfortunately, there're only samples for quick info and autocomplete features. No samples for ICommandHandler-s, haven't found any similar projects for Visual Studio for Mac as well
I agree the examples since Microsoft Visual Studio SDK documentation is horrible with no good examples of ICommandHandler.
I tried your exact code in visual studio 2022 on Windows 10 and the ExecuteCommand function is called.
So your code is fine.
I think the core problem here is that the ICommandHandler interface structure is somewhat newer and Microsoft did a poor job of properly checking for custom command handlers and adding calls.
I am trying to do a similar thing where I add an ICommandHandler to intercept the GoToDefinition command using an ICommandHandler, using this very similar code I can't get the ExecuteCommand function to fire ever.
I have been able to intercept commands using Microsofts older, yuckier DTE or DTE2 interface.
//provider constructor code
var dte2 = (DTE2)Package.GetGlobalService(typeof(DTE));
dte2.Events.CommandEvents.BeforeExecute += CommandEvents_BeforeExecute;
private static void CommandEvents_BeforeExecute(string guid, int id, object customIn, object customOut, ref bool cancelDefault)
{ //All events fired here use, the guid you want is likely
// Microsoft.VisualStudio.VSConstants.CMDSETID.StandardCommandSet97_string
// With an ID defined in
// Microsoft.VisualStudio.VSConstants.VSStd97CmdID
Debug.WriteLine("CommandEvents_BeforeExecute1 " + String.Format(
"dte2 GUID: {0}\nID: {1}\nIn: {2}\nOut: {3}",
guid, id, customIn, customOut));
}

Multiple Ribbons in Outlook Addin

I have an Outlook addin where I need to display a ribbon in the main Outlook window and in the Mail Read window as well. To do this I have added two ribbon xml files with the right markups in them. I then added a C# class that implements the Office.IRibbonExtensibility interface where I have implemented the GetCustomUI method which returns the right XML. Finally I did this in the ThisAddIn.cs class
protected override Office.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
try
{
_ribbon = new Ribbon();
return _ribbon;
}
catch (Exception e)
{
}
return null;
}
So far so good. The ribbons load and everything shows in correct place.
Now the problem is that this Ribbon.cs file is getting rather huge as all the callbacks live in this file. Is there a way to split the callbacks into multiple classes? So if I have a Ribbon1.xml and RIbbon2.xml can I have equivalent Ribbon1.cs and Ribbon2.cs?
OK so as it turns out this is really not possible in the VSTO model. You can really only have one class which must have all the event handlers in it. The recommended approach is to use partial classes and split the code between multiple code files.

How To Connect C# with ACAD 2010

Work on vs2008 C#, Need help to connect with autocad 2010, I follow the following steps to connect but it gives me an error.
I have to add a reference, so I go to references>>add reference>>[COM TAB]>>Autocad 2010 type library>>[OK]
I use two libraries:
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
And then I use the following code to connect with AutoCAD 2010:
namespace Sample_CSharp_Acad_connect
{
class Program
{
private static IAcadApplication oAcadApp = null;
private static string sAcadID = "AutoCAD.Application.18";
static void Main()
{
try //get a running AutoCAD instance if avaialbale
{
oAcadApp = (IAcadApplication)System.Runtime.InteropServices.Marshal.GetActiveObject(sAcadID);
}
catch(Exception) //none found so start a new instance
{
System.Type AcadProg = System.Type.GetTypeFromProgID(sAcadID);
oAcadApp = (IAcadApplication)System.Activator.CreateInstance(AcadProg);
}
if (oAcadApp != null)
{
oAcadApp.Visible = true; //could leave this false to hide Acad from the user
//do whatever with Acad
//oAcadApp.Quit();
}
}
}
Error message : error in getting object class COM for component CLSID
COM? Don't do it.
AutoCAD has a .NET API. See http://usa.autodesk.com/adsk/servlet/index?id=1911627&siteID=123112 for resources from Autodesk. Also see the wiki here for more info and links galore: https://stackoverflow.com/tags/autocad/info
How do you run this code? Is it an exe file? As far as I know, it is not so easy to control AutoCAD using an external progam. There are often lizening issues which prevent such operations.
It might be easier to access AutocAD functionality using a DLL. In that case the object model of AutoCAD can be accessed directly:
Dim theApp as Autodesk.AutoCAD.Interop.AcadApplications = Autodesk.AutoCAD.Interop.AcadApplication()
Debug.Print(theApp.Caption)
The SDK contains a lot of samples for DLLs which can be loaded into AutoCAD.
And: If it isn't really necessary, consider using .NET!

C# Add-in: How do you access runtime instances of objects while debugging?

I am developing an add in for C# that would only be used during debugging. Once instantiated, my add in needs to find all instances of a specific class or interface to display a graph about the data found.
How exactly can I find or access these objects in my extension? I have access to the DTE2 application object in my extension, but I'm not sure how to search the actual code being debugged by VS. I'm thinking I might somehow be able to use Reflection, but I'm not sure where to look.
Thanks.
I've implemented a plugin that searches through dlls in a given directory and finds classes that implement a particular interface. Below is the class I used to do this:
public class PlugInFactory<T>
{
public T CreatePlugin(string path)
{
foreach (string file in Directory.GetFiles(path, "*.dll"))
{
foreach (Type assemblyType in Assembly.LoadFrom(file).GetTypes())
{
Type interfaceType = assemblyType.GetInterface(typeof(T).FullName);
if (interfaceType != null)
{
return (T)Activator.CreateInstance(assemblyType);
}
}
}
return default(T);
}
}
All you have to do is initialize this class with something like this:
PluginLoader loader = new PlugInFactory<InterfaceToSearchFor>();
InterfaceToSearchFor instanceOfInterface = loader.CreatePlugin(AppDomain.CurrentDomain.BaseDirectory);
This type of operation isn't really possible from a Visual Studio plugin. The object alive when debugging live in the debugee process while your add-in is running in the Visual Studio process. It's not possible to access arbitrary objects across process boundaries in .Net.

TDD with filesystem dependencies

I have an integration test LoadFile_DataLoaded_Successfully(). And I want to refactor it to the unit test for breaking dependency with filesytem.
P.S. I am new in TDD:
Here are my production class :
public class LocalizationData
{
private bool IsValidFileName(string fileName)
{
if (fileName.ToLower().EndsWith("xml"))
{
return true;
}
return false;
}
public XmlDataProvider LoadFile(string fileName)
{
if (IsValidFileName(fileName))
{
XmlDataProvider provider =
new XmlDataProvider
{
IsAsynchronous = false,
Source = new Uri(fileName, UriKind.Absolute)
};
return provider;
}
return null;
}
}
and my test class (Nunit)
[TestFixture]
class LocalizationDataTest
{
[Test]
public void LoadFile_DataLoaded_Successfully()
{
var data = new LocalizationData();
string fileName = "d:/azeri.xml";
XmlDataProvider result = data.LoadFile(fileName);
Assert.IsNotNull(result);
Assert.That(result.Document, Is.Not.Null);
}
}
Any idea how to refactor it to break filesystem dependency
What you're missing here is inversion of control. For instance, you can introduce the dependency injection principle into your code:
public interface IXmlDataProviderFactory
{
XmlDataProvider Create(string fileName);
}
public class LocalizationData
{
private IXmlDataProviderFactory factory;
public LocalizationData(IXmlDataProviderFactory factory)
{
this.factory = factory;
}
private bool IsValidFileName(string fileName)
{
return fileName.ToLower().EndsWith("xml");
}
public XmlDataProvider LoadFile(string fileName)
{
if (IsValidFileName(fileName))
{
XmlDataProvider provider = this.factory.Create(fileName);
provider.IsAsynchronous = false;
return provider;
}
return null;
}
}
In the code above the creation of the XmlDataProvider is abstracted away using an IXmlDataProviderFactory interface. An implementation of that interface can be supplied in the constructor of the LocalizationData. You can now write your unit test as follows:
[Test]
public void LoadFile_DataLoaded_Succefully()
{
// Arrange
var expectedProvider = new XmlDataProvider();
string validFileName = CreateValidFileName();
var data = CreateNewLocalizationData(expectedProvider);
// Act
var actualProvider = data.LoadFile(validFileName);
// Assert
Assert.AreEqual(expectedProvider, actualProvider);
}
private static LocalizationData CreateNewLocalizationData(
XmlDataProvider expectedProvider)
{
return new LocalizationData(FakeXmlDataProviderFactory()
{
ProviderToReturn = expectedProvider
});
}
private static string CreateValidFileName()
{
return "d:/azeri.xml";
}
The FakeXmlDataProviderFactory looks like this:
class FakeXmlDataProviderFactory : IXmlDataProviderFactory
{
public XmlDataProvider ProviderToReturn { get; set; }
public XmlDataProvider Create(string fileName)
{
return this.ProviderToReturn;
}
}
Now in your test environment you can (and probably should) always create the class under test manually. However, you want to abstract the creation away in factory methods to prevent you having to change many tests when the class under test changes.
In your production environment however, it can become very cumbersome very soon when you manually have to create the class. Especially when it contains many dependencies. This is where IoC / DI frameworks shine. They can help you with this. For instance, when you want to use the LocalizationData in your production code, you might write code like this:
var localizer = ServiceLocator.Current.GetInstance<LocalizationData>();
var data = data.LoadFile(fileName);
Note that I'm using the Common Service Locator as an example here.
The framework will take care of the creation of that instance for you. Using such a dependency injection framework however, you will have to let the framework know which 'services' your application needs. For instance, when I use the Simple Service Locator library as an example (shameless plug that is), your configuration might look like this:
var container = new SimpleServiceLocator();
container.RegisterSingle<IXmlDataProviderFactory>(
new ProductionXmlDataProviderFactory());
ServiceLocator.SetLocatorProvider(() => container);
This code will usually go in the startup path of your application. Of course the only missing piece of the puzzle is the actual ProductionXmlDataProviderFactory class. Here is it:
class ProductionXmlDataProviderFactory : IXmlDataProviderFactory
{
public XmlDataProvider Create(string fileName)
{
return new XmlDataProvider
{
Source = new Uri(fileName, UriKind.Absolute)
};
}
}
Please also not that you will probably don't want to new up your LocalizationData in your production code yourself, because this class is probably used by other classes that depend on this type. What you would normally do is ask the framework to create the top most class for you (for instance the command that implements a complete use case) and execute it.
I hope this helps.
The problem here is that you are not doing TDD. You wrote the production code first, and now you want to test it.
Erase all that code and start again. Write a test first, and then write the code that passes that test. Then write the next test, etc.
What is your goal? Given a string that ends in "xml" (why not ".xml"?) you want an XML data provider based upon a file whose name is that string. Is that your goal?
The first tests would be the degenerate case. Given a string like "name_with_wrong_ending" your function should fail. How should it fail? Should it return null? Or should it throw an exception? You get to think about this and decide in your test. Then you make the test pass.
Now, what about a string like this: "test_file.xml" but in the case where no such file exists? What do you want the function to do in that case? Should it return null? Should it throw an exception?
The simplest way to test this, of course, is to actually run the code in a directory that does not have that file in it. However, if you'd rather write the test so that it does not use the file system (a wise choice) then you need to be able to ask the question "Does this file exist", and then your test needs to force the answer to be "false".
You can do that by creating a new method in your class named "isFilePresent" or "doesFileExist". Your test can override that function to return 'false'. And now you can test that your 'LoadFile' function works correctly when the file doesn't exist.
Of course now you'll have to test that the normal implementation of "isFilePresent" works correctly. And for that you'll have to use the real file system. However, you can keep file system tests out of your LocalizationData tests by creating a new class named FileSystem and moving your 'isFilePresent' method into that new class. Then your LocalizationData test can create a derivative of that new FileSystem class and override 'isFilePresent' to return false.
You still have to test the regular implementation of FileSystem, but that's in a different set of tests, that only get run once.
OK, what's the next test? What does your 'loadFile' function do when the file does exist, but does not contain valid xml? Should it do anything? Or is that a problem for the client? You decide. But if you decide to check it, you can use the same strategy as before. Make a function named isValidXML and have the test override it to return false.
Finally we need to write the test that actually returns the XMLDataProvider. So the final function that 'loadData' should call, after all those other function is, createXmlDataProvider. And you can override that to return an empty or dummy XmlDataProvider.
Notice that in your tests you have never gone to the real file system and really created an XMLDataProvider based on a file. But what you have done is to check every if statement in your loadData function. You've tested the loadData function.
Now you should write one more test. A test that uses the real file system and a real valid XML file.
When I look at the following code:
public class LocalizationData
{
private static bool IsXML(string fileName)
{
return (fileName != null && fileName.ToLower().EndsWith("xml"));
}
public XmlDataProvider LoadFile(string fileName)
{
if (!IsXML(fileName)) return null*;
return new XmlDataProvider{
IsAsynchronous = false,
Source = new Uri(fileName, UriKind.Absolute)
};
}
}
(* I'm not thrilled about the return null. Yuck! that smells.)
Anyway, I would ask the following questions to myself:
What could possibly break with this code? Are there any complex logic or fragile code that I should safe-guard myself against?
Is there anything complicated to understand or worth highlighting via a test that the code is not able to communicate?
Once I've written this code, how frequently do I think I'll revisit (change) it?
The IsXML function is extremely trivial. Probably does not even belong to this class.
The LoadFile function creates a synchronous XmlDataProvide if it gets a valid XML filename.
I would first search who uses LoadFile and from where fileName is being passed. If its external to our program, then we need some validation. If its internal and somewhere else we are already doing the validation, then we are good to go. As Martin suggested, I would recommend refactoring this to take Uri as the parameter instead of a string.
Once we address that, then all we need to know is if there is any special reason why the XMLDataProvider is in the synchronous mode.
Now, is there anything worth testing? XMLDataProvider is not a class we built, we expect it to work fine when we give a valid Uri.
So frankly, I would not waste my time writing test for this. In the future, if we see more logic creeping in, we might revisit this again.
In one of my (Python) projects, I assume that all unit tests are run in a special directory that contains the folders "data" (input files) and "output" (output files). I'm using a test script that first checks whether those folders exists (i.e. if the current working directory is correct) and then runs the tests. My unit tests can then use relative filenames like "data/test-input.txt".
I don't know how to do this in C#, but maybe you can test for existence of the file "data/azeri.xml" in the test SetUp method.
It has nothing to do with your testing (x), but consider using Uri instead of String as parameter type for your API.
http://msdn.microsoft.com/en-us/library/system.uri(v=VS.100).aspx
x: I think Steven covered that topic pretty very well.
Why do you use the XmlDataProvider? I don't think that it's a valuable unit test, as it stands now. Instead, why don't you test whatever you would do with that data provider?
For example, if you use the XML data to load out a list of Foo objects, make an interface:
public interface IFooLoader
{
IEnumerable<Foo> LoadFromFile(string fileName);
}
You can then test your implementation of this class using a test file you generate during a unit test. In this way you can break your dependency on the filesystem. Delete the file when your test exits (in a finally block).
And as for collaborators that use this type, you can pass in a mock version. You can either hand code the mock, or use a mocking framework such as Moq, Rhino, TypeMock or NMock. Mocking is great, but if you're new to TDD then it's fine to hand code your mocks while you learn what they're useful for. Once you have that, then you are in a good position to understand the good, bad and ugly of mocking frameworks. They can be a bit gnarly to work with when you're starting TDD. Your mileage may vary.
Best of luck.
In this case, you are basically at the lower level of dependency. You are testing that a file exist and that an xmlprovider can be created with the file as source.
The only way that you could break the dependency, would be to inject something to create the XmlDataProvider. You could then mock it to return a XmlDataProvider that you created (as opposed to read). As simplistic example would be:
class XmlDataProviderFactory
{
public virtual XmlDataProvider NewXmlDataProvider(string fileName)
{
return new XmlDataProvider
{
IsAsynchronous = false,
Source = new Uri(fileName, UriKind.Absolute)
};
}
class XmlDataProviderFactoryMock : XmlDataProviderFactory
{
public override XmlDataProvider NewXmlDataProvider(string fileName)
{
return new XmlDataProvider();
}
}
public class LocalizationData
{
...
public XmlDataProvider LoadFile(string fileName, XmlDataProviderFactory factory)
{
if (IsValidFileName(fileName))
{
return factory.NewXmlDataProvider(fileName);
}
return null;
}
}
[TestFixture]
class LocalizationDataTest
{
[Test]
public void LoadFile_DataLoaded_Succefully()
{
var data = new LocalizationData();
string fileName = "d:/azeri.xml";
XmlDataProvider result = data.LoadFile(fileName, new XmlDataProviderFactoryMock());
Assert.IsNotNull(result);
Assert.That(result.Document, Is.Not.Null);
}
}
Using an injection framework could simplify the call to LoadFile by injecting the factory in the class constructor or elsewhere.
I Like #Steven's answer except I think He didn't go far enough:
public interface DataProvider
{
bool IsValidProvider();
void DisableAsynchronousOperation();
}
public class XmlDataProvider : DataProvider
{
private string fName;
private bool asynchronousOperation = true;
public XmlDataProvider(string fileName)
{
fName = fileName;
}
public bool IsValidProvider()
{
return fName.ToLower().EndsWith("xml");
}
public void DisableAsynchronousOperation()
{
asynchronousOperation = false;
}
}
public class LocalizationData
{
private DataProvider dataProvider;
public LocalizationData(DataProvider provider)
{
dataProvider = provider;
}
public DataProvider Load()
{
if (provider.IsValidProvider())
{
provider.DisableAsynchronousOperation();
return provider;
}
return null;
}
}
By not going far enough I mean that he didn't follow the Last Possible Responsible Moment. Push as much down into the implemented DataProvider class as possible.
One thing I didn't do with this code, is drive it with unit tests and mocks. That is why you're still checking the state of the provider to see if it is valid.
Another thing is that I tried to remove the dependencies on having the LocalizationData know that the provider is using a file. What if it was a web service or database?
So first of all let us understand what we need to test. We need to verify that given a valid filename, your LoadFile(fn) method returns an XmlDataProvider, otherwise it returns null.
Why is the LoadFile() method difficult to test ? Because it creates a XmlDataProvider with a URI created from the filename. I have not worked much with C#, but am assuming that if the file does not actually exist on the system, we will get an Exception. The real problem is, your production method LoadFile() is creating something which is difficult to fake. Not being able to fake it is a problem because we cannot ensure the existence of a certain file in all test environments, without having to enforce implicit guidelines.
So the solution is - we should be able to fake the collaborators (XmlDataProvider) of the loadFile method. However, if a method creates it's collaborators it cannot fake them, hence a method should never create it's collaborators.
If a method does not create it's collaborators, how does it get them ? - In one of these two ways:
They should be injected into the method
They should be obtained from some factory
In this case it does not make sense for the XmlDataProvider to be injected into the method, since that is exactly what it is returning. So we should get it from a global Factory - XmlDataProviderFactory.
Here comes the interesting part. When your code is running in production, the factory should return an XmlDataProvider, and when your code is running in a test environment, the factory should return a fake object.
Now the only part of the puzzle is, how to ensure that the factory behaves in different ways in different environments ? One way is to use some properties which have different values in both environments, and the other way is to configure the factory for what it should return. I personally prefer the former way.
Hope this helps.
This time, don't try to break your dependency on the file system. This behavior clearly depends on the file system, and appears to be at the integration point with the file system, so test it with the file system.
Now, I second Bob's advice: throw this code away and try test-driving it. It makes for great practice and is exactly how I trained myself to do it. Good luck.
Instead of returning XmlDataProvider which ties you a specific tech, hide this implementation detail. It looks like you need a repository Role to
LocalizationData GetLocalizationData(params)
You can have an implementation for this Role, which internally uses Xml. You'd need to write integration tests to test whether XmlLocalizationDataRepository can read actual Xml data stores. (Slow).
The rest of your code can mock out GetLocalizationData()

Categories