Unity Strategy for MEF

The Prism 4.0 CTP has support for Unity and MEF, but not both at the same time.   In my case this is a problem because I'd like to use MEF for what it is designed for (extensibility / add-ins) and use Unity for what it was designed for (dependency injection).

To achive my requirements I'm going to use the extensibility hooks within Unity, more specifically; a strategy.   Surprisingly the power of strategies are not emphasized and there is not a lot of documentation on the subject.  The "walkthrough" in the Unity 2.0 documentation gives an example of how to create an extension and strategy but I found the Unity unit test to be more complete (I used the SpyExtension as an example on how to construct my MEFStrategy).

The first test below PublicFromPublic() is a MEF unit test that I revamped to test my MEFContainer, which encapsulates and simplifies working with the MEF container and CompositionBatch within the strategy.

The second test lets the Unity container drive and depends on the strategy to add the parts to the batch within the MEFContainer.  The test verifies that the parts are not yet composed prior to executing Compose() and that they are composed following the Compose() method.

This strategy is still in its infant stages, I only started this weekend and have a ways to go before I plug it into Prism 4.0. 


using System.ComponentModel.Composition;
using MEFContrib.Base;
using MEFContrib.Strategy;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestStrategyToLoadMEF
{
    [TestClass]
    public class MEFStrategyFixture
    {
        [TestMethod]
        public void PublicFromPublic()
        {
            var importer = new AllPublicImportOnly { ImportA = 1, ImportB = 1 };
            var exporter = new AllPublicExportOnly { ExportA = 5, ExportB = 10 };
            new MEFContainer()
                .AddPart(importer)
                .AddPart(exporter)
                .Compose();
            Assert.AreEqual(5, importer.ImportA);
            Assert.AreEqual(10, importer.ImportB);
        }
        [TestMethod]
        public void TestStrategyToLoadMEF()
        {
            var mefContainer = new MEFContainer();
            var mefExtension = new MEFStrategyExtension(mefContainer);
 
            // Instantiate unity container and add MEF extension
            var container = new UnityContainer().AddExtension(mefExtension);
            // Initialize MEF parts
            var importer = new AllPublicImportOnly { ImportA = 1, ImportB = 2 };
            var exporter = new AllPublicExportOnly { ExportA = 5, ExportB = 10 };
            // Buildup importer/exporter (strategy kicks in)
            container.BuildUp(importer);
            container.BuildUp(exporter);
            // Register importer instance emulating use in other area of app
            container.RegisterInstance<AllPublicImportOnly>(importer);
            // Resolve MEF and Unity classes
            var importResolved = container.Resolve<AllPublicImportOnly>();
            var classThatImports = container.Resolve<TestClassThatImports>();
            // MEF parts have not yet been composed (Strategy adds them to batch)
            Assert.AreEqual(1, importResolved.ImportA);
            Assert.AreEqual(2, importResolved.ImportB);
            
            // Compose MEF parts
            mefContainer.Compose();
            // After composition exported values should be in place
            Assert.AreEqual(5, importResolved.ImportA);
            Assert.AreEqual(10, importResolved.ImportB);
            // Unity setter injection 
            Assert.AreEqual(20, classThatImports.ImportedClass.TestValue);
        }
    }
    
    public class TestClassThatImports
    {
        [Dependency]
        public TestClassToImport ImportedClass { getset; }
    }
    public class TestClassToImport
    {
        public TestClassToImport()
        {
            TestValue = 20;
        }
        public int TestValue { getset; }
    }
    public class AllPublicImportOnly
    {
        [Import("a")]
        public int ImportA { getset; }
        [Import("b")]
        public int ImportB { getset; }
    }
    public class AllPublicExportOnly
    {
        [Export("a")]
        public int ExportA { getset; }
        [Export("b")]
        public int ExportB { getset; }
    }
}
SOURCE: TestStrategyToLoadMef.zip (11.62 mb)
 

Tags: , ,
Categories: MEF | Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

MEF Container - encapsulating and simplifying

With MEF 2 Preview 1 released (July 2010) it is time to dig in and examine it under the hood, particularly .NET 4.0 capabilities.   Fortunately the Patterns & Practices teams have a standard of providing unit test which make the task sometimes easier than reading (or waiting on) the documentation.

I'll start from the top and work my way down - I am currently on the System\ComponentModel\AttributedModel\AllowNonPublicCompositionTests.cs

        [TestMethod]
        public void PublicFromPublic()
        {
            var container = ContainerFactory.Create();
            CompositionBatch batch = new CompositionBatch();
            var importer = new AllPublicImportOnly();
            batch.AddPart(importer);
            batch.AddPart(new AllPublicExportOnly() { ExportA = 5, ExportB = 10 });
            container.Compose(batch);
            Assert.AreEqual(5, importer.ImportA);
            Assert.AreEqual(10, importer.ImportB);
        }

Up to this point my adventures with MEF have been confined to the attributes import, export, etc.   I was encourage early in the game to see programmatic support for MEF.  My objective now is to understand MEF from this angle so that I create a Unity Strategy for Prism that will permit Prism, Unity and MEF to play nicely under one roof.  Since I learn by doing I decided to create a MEFContrib project that will simplify life (while making it easier to understand the code).   The MEFContainer and CompositionBatchExtension classes are the first classes added to this project.

For example, the following code performs the exact same process as the above code:

        [TestMethod]
        public void PublicFromPublicUsingMEFContainer()
        {
            var importer = new AllPublicImportOnly();
            var exporter = new AllPublicExportOnly{ ExportA = 5, ExportB = 10 };
            new MEFContainer()
                .AddPart(importer)
                .AddPart(exporter)
                .Compose();
            Assert.AreEqual(5, importer.ImportA);
            Assert.AreEqual(10, importer.ImportB);
        }

The above was Added to AllowNonPublicCompositionTests.cs after adding reference to MEFContrib.

The contents of MEFContrib follow:


using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace MEFContrib.Base
{
    /// <summary>
    ///  MEF Container
    /// </summary>
    public class MEFContainer
    {
        private CompositionBatch batch = new CompositionBatch();
        private CompositionContainer container = new CompositionContainer();
        /// <summary>
        /// Adds the part.
        /// </summary>
        /// <param name="part">The part.</param>
        /// <returns></returns>
        public MEFContainer AddPart(object part)
        {
            batch.AddPart(part);
            return this;
        }
        /// <summary>
        /// Composes this instance.
        /// </summary>
        public void Compose()
        {
            container.Compose(batch);
        }
    }
}

namespace MEFContrib.Base.Extentions
{
    public static class CompositionBatchExtension
    {
        /// <summary>
        /// Composes the specified batch.
        /// </summary>
        /// <param name="batch">The batch.</param>
        /// <param name="container">The container.</param>
        /// <returns></returns>
        public static MEFContainer Compose(this MEFContainer container)
        {
            container.Compose();
            return container;
        }
    }
}

Tags: ,
Categories: MEF


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Visual Studio 2010 - missing Use Case template

When I attempted to create a Use Case diagram it was not available in the list (as shown below).   I found the following link instrumental to restoring this template.  I dropped to Visual Studio Command prompt and executed devenv /installvstemplates and waited (patience is required).  After it completed I had my template!  

http://msdn.microsoft.com/en-us/library/0fyc0azh.aspx 

Excerpt from the above link follows:

Available templates may vary according to Visual Studio version, SKU, installation options, and other customizations. If you are missing a template that comes with your installation, run devenv.exe with the /installvstemplates switch. For more information, see How to: Restore Default Project Templates.


Tags:
Categories: Visual Studio 2010


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Statistics Mode - Calculating with LINQ

Measures of central tendency, aka averages, is an attempt to find a single value that represents a series of values.  Mode is a kind of average in statistics that is defined as the most frequently occurring value.  [1][2] 

In the following collection there are 3 "F", 2 "Female", 3 "M" and 1 "Male".   Since the "most frequently occurring value is both "F" and "M" (both have 3) this collection is bimodal [2]. Had there been more than two then it would have been multimodal [2].   As a result Mode cannot be used as a  measure of central tendency for this data [1].

However, we can see that there are really 5 females and 4 males, the reality is that the Mode for the following collection is Female  (the most frequently observed data value).   To get the proper mode we first have to simplify this parameter of the population.

Note: Dump() is an extension method of LinqPad that displays the contents.

Below you'll see we'll generate a new list (genderLetters) composed of only a single character; we then sort the list so that we can visually see the results.

With a couple of lines of LINQ code above we can get a clean sorted list that better represents this parameter of the population.  All that remains is to process the counts so that we can determine the Mode - below is all of the LINQ source code that is required:

The GetMode() method above was originally written for an int array provided by reference [2], thus the naming conventions used within the method.   Note in the image below that we use the very same method GetMode() to process our list of integers which produces a record representing the Mode for the array - in this case there are three sixes which is the most frequently observed data value.

Generics permit us to use the same LINQ query for both strings as well as int.  Note below that I was able to simply use GetMode(season) because "int" was inferred where above we had to explicitly provide the type, e.g., GetMode<string>(genderLetters) - required because the compiler was not able to infer the type from the dynamically generated list.

Below we use query.First() to get the Mode since we are sorted in descending order; likewise above we could have done a g.First() to receive it's Mode. 

Above source code Mode.linq (1.29 kb) 

Go to http://www.linqpad.net/ to get a free program to run the source code.  After finding this gem of a program I purchased the book and was not disappointed; it is one of the few books I own that I reguarly use for reference.

References

1. ^ Clark/Schkade. "Statistical Analysis for Administrative Decisions". 
    South-Western Publishing Co. 1983. pp. 24-26.
2. ^  http://www.statcan.gc.ca/edu/power-pouvoir/ch11/mode/5214873-eng.htm

VS2010 Source code w/Unit Test for int, double and string =>  Statistics.Library.zip (56.78 kb)


Tags: ,
Categories: Statistic


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

PRISM V4 Drop 2 : MVPVM Modularity with MEF

Sample Application: ModularityWithMef.zip (4.95 mb)

Although I have been a hard-core Unity (Dependency Injection) cronie since its conception I have to admit I was very pleased with MEF extensions to PRISM.  However, it did force me to rethink some design strategies that I've used since the Smart Client Software Factory - such as using generics to quickly wire-up base classes (you can't use generics with attributes).

Somewhat reluctant at first I scraped my earlier prototype/design and moved forward with a new design that is centered around MEF and PRISM V4 Drop 2.   I'll have to build an infrastructure that will minimize refactoring when PRISM V4 is released; particularly since PRISM, MEF and Unity will serve as the main tools.

The sample that is provided in the PRISM V4 Drop 2 looks as follows with the exception of the View on the right.  I added a new new "Hello World" view utilizing the MVPVM pattern; I use PRISM/MEF to wire-up the infrastructure.  

Note: Module F Imports two Business Logic Layers (DoctorBLL/PatientBLL) which in turn Import their respective Data Access Layers.  It then uses these, within its presenter, to populate the view model properties that the two ComboxBoxes are bound to. 

The end result after refactoring the sample is as follows:

  • The Model instantiates the Presenter 
  • The Presenter instantiates the View and wires up the view model as applicable

After wire-up the Presenter handles all business logic (you'll find no code in the code-behind files).   Below is all of the code required to wire-up the module A view with A)dd, E)dit, D)elete and P)rint buttons.   Modules A and E both use the same CRUDControl and each have their own CRUD View Models (derived from CRUDViewModelBase) which permit base functionality to be overridden, i.e., notice that Module E does not have a P)rint button.   The only wire-up required for the CRUDControl is shown on line 23 below where the DoctoCRUDViewModel.ParentViewModel is set with a reference.

The only issue I ran into, which will result in a message in the user forum is I couldn't figure out how to [Import] parts in the Bootstrapper - so currently there is some code in the MainWindow code-behind but as soon as I work this out I'll move what little code remains there into the Presenter.

Sample Application: ModularityWithMef.zip (4.95 mb)


Tags:
Categories: MEF | MVPVM | Prototype


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

PRISM 2.2: can't use StaticResource when resource is in App.xaml

I lost count of the number of variations of "can't use StaticResource" that I BING'd for over the last couple of days; countless hours banging my head against the desk.

This adventure started when I created a prototype from the DirectoryLookupModule sample from the Prism 2.2 package (ref this prototype link).  As you can see from the link it went through a major transformation and it wasn't until the MVPVM infrastructure was in place (with Business and Data access layers consuming a simple service) that I started to implement a DataTemplate.

The problem was I couldn't access my DataTemplate from the merge dictionary entry for App.xaml UNLESS I made it a DynamicResource.  Where this worked just fine the pit-bull side of me had to know why....

It wasn't until the second day that I noticed that "all" of the resources in this sample application were using DynamicResource, it was this revelation that started the road to discovery.   At the end of the road was the following obsure little declaration in the constructor.   The Prism bootstrapper was being loaded during the constructor versus OnStartup!  This little oversite prevents the StaticResource from being usable in the Shell or any of its Modules.

The happy ending on this story was that while updating the Prism forum with this tidbit (it was where I started my journey to discover the cause of this odd-ball bug) I noticed that Prism 4 had a Drop 2 so  naturally  I downloaded it and at first was somewhat dismayed that Unity was no where in the picture but was shortly taken aback by MEFs angle at the problem; it was very cool to say the least and I am now in the process of moving my MVPVM prototype to Prism 4.

 


Tags: , , ,
Categories: MEF | MVPVM


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

MVPVM: Sharing a CRUD control with multiple views

The object is to reuse CRUD logic, such as enabling/disabling buttons, setting IsEditing flags that XAML can bind to, etc, without polluting our view models.   For this we have a CRUDViewModelBase class that we derive from and set flags based on our needs - in the example below (right image) we set IsPrintVisible to false effectively hiding the Print button for the Patient (Module D in this prototype application DirectoryLookupModularity.zip (5.82 mb) ).

Note that the DoctorViewModel and PatientViewModel have overrides for each of the button clicks as well as a reference to it's parent view model and shared criteria view model.   The CRUD logic is completely decoupled and can be encapsulated within each view model for each concern; we have a clear separation of concerns (SOC).

Once we assign the PatientCRUDViewModel to Module D's View we can see below that the [P] button is not visible.   The default behavior is to have all buttons visible as shown for Module A

Since the Modules job (ModuleA.cs in image below) to load the Presenter, and the Views (DefaultViewA.xaml) have no code in their code-behinds, it is the Presenter's (DoctorPresenter.cs) responsibility to execute business logic as required.  Below we can see where the doctorCrudVm.ParentViewModel is provided a reference to its parent view. 

A single presenter / view can handle multiple CRUD requirements easily using the CRUDControl.

Note: Where a View can only have one view model, a view model can be shared across numerous views (reused).  In the case of our sample application the Shell and Modules B and C all share the CriteriaViewModel which is defined in the bootstapper as a singleton (the MVPVM framework represented in the sample link above easily supports this). 

It is the ability to reuse this domain object, across multiple views and modules, that dictates our project structure.  The PrototypeApp.Interface contains all the classes used by this application (ideally I would have the Business and Data layers in their own projects so they can be reused across multiple solutions but this is just a sample prototype).

A key point not to miss here is that you don't want to populate your view model domain objects with business logic that does not pertain to managing its view.

DirectoryLookupModularity.zip (4.91 mb)


Tags: , , ,
Categories: MVPVM | Prototype


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

MVPVM: Integration testing using the Presenter

The MVPVM pattern lends itself to effective integration/unit testing.   Since their is no code in the code-behind and the Presenter processes all business logic against the ViewModel and View it is the best component to perform integration test against. 

In the following application (download from this link DirectoryLookupModularity.zip (5.82 mb)) there are three view models:

  1. CriteriaViewModel - utilized by views E, B and C
  2. DoctorViewModel - utilized by view A
  3. PatientViewModel - utilized by view D

The MVPVM framework used for the attached application consistently uses the following for bootstrapping modules:

The ModuleBase<TPresenter> (see below image) instantiates the specified Presenter, e.g., on line 14 below we identify the "DoctorPresenter" as the presenter.

The PresenterBase<TView, TViewModel> (see below image) specifies the View and it's ViewModel which in this case is DefaultViewA and DoctorViewModel respectively.  On line 23 we register the view (DefaultViewA) with the TopLeft region which was declared in the Shell's XAML.  The remaining logic is the code required to wire-up a CRUD control and to get the current module load counter value so that we can see that the module dependency attributes are working correctly.

These baseclasses do all of the wiring up so that we can focus on business rules; we don't spend a lot of time getting our module up and ready for the requirements at hand.

The integration test for Module A's presenter is shown below (lines 46-52); it verifies that the infrastructure properly wired up the View and ViewModel. 

Did you notice that on line 24 above we set the container to null and on the following line use the container.RegisterServices() method?   On the surface this may look odd but it lends itself to testing the Prism environment.

We use the same RegisterServices in our bootstrapper as we do in our integration/unit test - we do this to ensure our environments match for testing purposes.  To accomplish this we use a IUnityContainer Extension class (IUnityContainerExtension), the only time container will be null is during testing so we instantiate a MockBootstrapper (lines 25-27 below).   From that point on we have the same registrations to ensure our test will run without complaint.


Tags: , , ,
Categories: MVPVM | Prototype


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

WPF assembly: XmlnsDefinition - identify types for XAML usage

If a picture says a thousand words then the following should save me some typing as to the value of XmlnsDefinition (reference line 5 below) - it provides an easy to remember Url mapping to your namespaces. 

My PrototypeApp (born from the Prism DirectoryLookupModularity sample) has an Prototype.Interface project where much of the application specific code resides.   Within the AssemblyInfo.cs file (under the Properties folder) I was able to map all of the applicable namespaces to a single, easy to remember, url.

Excerpt from AssemblyInfo.cs follows: 

[assemblyAssemblyVersion("1.0.0.0")]
[assemblyAssemblyFileVersion("1.0.0.0")]
[assemblyXmlnsDefinition(http://www.Global-Webnet.com/PrototypeApp,
                            "PrototypeApp.Interface.Constants")]
[assemblyXmlnsDefinition(http://www.Global-Webnet.com/PrototypeApp
                           "PrototypeApp.Interface.ViewModels")]
[assemblyXmlnsDefinition(http://www.Global-Webnet.com/PrototypeApp,
                            "PrototypeApp.Interface.Controls")]
[assemblyXmlnsDefinition(http://www.Global-Webnet.com/PrototypeApp
                           "PrototypeApp.Interface.Converters")]

Demo source code follows: DirectoryLookupModularity.zip (5.82 mb)


Tags: , ,
Categories: Prototype


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Unit Testing ASP.NET/Client Application Service / Programmatically Starting Web Development Server (WebDev.WebServer.exe)

What is seemingly a very simple process turned into quite the adventure - a costly one in terms of following dead-ends and beating my head against the wall - I first started with the programmatically started service (failing miserably) and evolved into the attribute driven approach which I finally got to work but it had constraints.....

I will detail how to make both methods work, highlighting areas left out of available blogs and research material that will result in errors that yield no answers on the internet.  

The adventure started with an annoying problem with my EHR unit test - I have a number of test that test the Client Application Service (for security) and if I don't manually start up the ApplicationService web service they will fail - this morning I rolled up my sleeves and decided to automate this process so at any time I can run all test in solution and have the service automatically start for the test that depend on it.

Below shows the syntax for the StartWebApplication() TestContext extension method that does the job of starting up the service during test initialize programmatically. 

Before going into more detail the following source demonstrates how to use the attribute method for starting the ApplicationService:

THE KEY to using attributes is to first ensure you have the namespace available - you'll find many resources that will correctly inform you that you must use the following:

using Microsoft.VisualStudio.TestTools.UnitTesting.Web;

However, what is not easily found is the DLL that this unit test resides in!!!   After a long search and destroy mission (online failed) I started searching the Microsoft.VisualStudio DLLs and found it in the Microsoft.VisualStudio.QualityTools.WebTestFramework 

A second piece of information that can really eat your lunch if it escapes you is that you MUST have a DEFAULT.ASPX file in the service!!!  Since I was using a Client Application Service (which doesn't even have a service, never mind a default.aspx file) I ran into the errors you'll see below that affected both the programmatic method as well as the attribute method.   Ensure you have a Default.aspx file.

CONSTRAINTS

I could be missing something but I could not get a breakpoint to work on the unit test that had this attribute - this was unacceptable but at least I got the web development server to start automajically (for the first time) so I was going to make it work.   I decided to have an initialize (empty) service that would start the service so that it was available for the rest of the unit test.

I then ran into a problem - you cannot control the order of your test (outside of an ordered test).  I want to be able to "run all test in solution" and have it work (which it currently does).   I saw blogs that tell you that you can use the Priority attribute but it doesn't work - later this was confirmed on the MSDN site that holds the information for this attribute; it clearly states that this is not used by the test engine and is only for developer use.

My work-around; I found that the same test always is the first test to run so I put the attribute on it :)  Ugly work-around but it works.   You'll find it on my CanGetCloudContainer() unit test which is always the first test to run in the solution.   Later I was able to get the programmatic approach to work consistently (by adding a default.aspx file) so I really don't need this solution but keep it in there as a code reference (for this blog).   I did code the TestContextExtension so that if a WebDev.Server is available it will not attempt to programmatically load it.   This supports both "all unit test in solution" (attribute) and the programmatic approach (if running only that test fixture during development).

HEAD-BANGERS

ERROR:  The ASP.NET Web application at 'C:\_\_EHR\Layers\Service\GWN.EHR.ApplicationService' is already configured for testing by another test run. Only one test run at a time can run tests in ASP.NET. If there are no other test runs using this Web application, ensure that the Web.config file does not contain an httpModule named HostAdapter.

This error occurs if you are using the attribute method and you crashed out of the unit test.   Behind the scenes when the test starts the Web.Config is modified; the HostAdapter is added to it.  When the test are all completed it is removed.  If you crash out of the test and this is not removed then you will see the above error.   To watch this at work simply load your Web.Config of your service and run the test - you will be notified when the Web.Config file is changed (first to add and the second to remove the HostAdapter statement).

ERROR:  The Web request 'http://localhost:2035/AppService' completed successfully without running the test. This can occur when configuring the Web application for testing fails (an ASP.NET server error occurs when processing the request), or when no ASP.NET page is executed (the URL may point to an HTML page, a Web service, or a directory listing). Running tests in ASP.NET requires the URL to resolve to an ASP.NET page and for the page to execute properly up to the Load event. The response from the request is stored in the file 'WebRequestResponse_CanGetCloudBlobConta.html' with the test results; typically this file can be opened with a Web browser to view its contents.

The above error occurs if the the web application/service does not have a Default.aspx file.   If you debug the test you'll see the ASP.NET Web Development Server load, the test will fail and then the Web Development server will close.

With the Default.aspx file missing you can see the "in progress" test below fails for a "Configuration Error".   At other times I could get the programmatic approach to work without the default.aspx however I will ensure I have one to ensure I don't stumble upon the following error again:

 

The error for CanGetCloudBlobContainer (attribute load of Web Development Server) above had the following "The web site could not be configured correctly" error also: 

Source code for TestContext extension that loads the WebDev.WebServer.exe follows:

using System.Diagnostics;

using System.Linq;

using Microsoft.VisualStudio.TestTools.UnitTesting;

 

namespace GWN.Library.Tests.Extensions

{

    public static class TestContextExtension

    {

        private static Process _currentProcess;

 

        public const string WebDevWebServerExe =
            @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\WebDev.WebServer.exe";

 

        public static string StartWebApplication(this TestContext testContext,

            string appName, string port, string fullAppPath)

        {

            if (_currentProcess != null)

                return null;

 

            // If other processes, i.e., attribute process, loaded webserver

            // then don't run this process (it is already available).  We only

            // run one service at this point so we'll worry about multiple ones

            // when the need arises..

            if (Process.GetProcesses()

                .Any(process => process.ProcessName.Contains("WebDev.WebServer")))

                    return null;

 

            var fullWebPath = string

                .Format("/port:{0} /path:\"{1}{2}\" /vpath:\"/{3}\"",

                       port,

                       testContext.GetRootPath(),

                       fullAppPath,

                       appName);

 

            var startinfo = new ProcessStartInfo(WebDevWebServerExe, fullWebPath)

                {

                    WindowStyle = ProcessWindowStyle.Hidden,

                };

 

            _currentProcess = Process.Start(startinfo);

 

            return fullWebPath;

        }

 

        public static string GetRootPath(this TestContext testContext)

        {

            var offset = testContext.TestDir.IndexOf("TestResults");

            var path = testContext.TestDir.Substring(0, offset);

            return path;

        }

    }

}

ATTRIBUTE APPROACH (full source since image is cut off)

/// <summary>

/// Determines whether this instance [can get BLOB container].

/// </summary>

[TestMethod]

[HostType("ASP.NET")]

[AspNetDevelopmentServerHost(
   @"C:\_\_EHR\Layers\Service\GWN.EHR.ApplicationService", "/AppService")]

[UrlToTest("http://localhost:2035/AppService")]

public void CanGetCloudBlobContainer()

{

    // Get list

    var blobList = client.ReadContainerList();

 

    // Get first container

    var blobContainer = blobList.FirstOrDefault();

 

    Assert.IsNotNull(blobContainer);

 

    // Use first container (name) to get container from list

    var cloudBlobContainer = client.ReadContainer(blobContainer.Name);

 

    // Assert the names match

    Assert.AreEqual(blobContainer.Name, cloudBlobContainer.Name);

}


Tags: , ,
Categories:


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know