Saturday, 10 May 2014

Managed Extensibility Framework Step by Step

Introduction:

As we know MEF is Microsoft Extensibility Framework. It helps in developing loosely coupled, extensible applications. So it leverage to plug in components in already developed application. I am not going to discuss much about the theoretical discussion rather step by step guide to how to use this framework in a sample application.

MEF works on OPEN-CLOSED Principle of the SOLID principles which is as below

Module should be closed for modification but open for extension.


MEF basic terminology:

1. Catalog : contain components those are to be plugged-in 
2. Exports: These are contracts or plug-in which can be composed in the application
3. Imports: These are properties or socket where components can be plugged-in.
4. Composition: it composes all together.

Application Brief:

It is a Movie Search Windows Application and Form will have design as shown below. Initially it can search only English Comedy movies and later we will add more components to search the Adventure and Drama movies as well.

Steps:

Step 1. Create a Window Application and named it MovieSearchApplication.


Step 2. Add one label with text property as "Enter movie title" and textbox to enter Title of the movie and radio buttons to select movie categories and richtexbox to display the movie details as shown below. Add one button and enter text property as Search.


Step 3.  Add one Class Library project and named it MovieDetailContract.

Step 4. Delete class1.cs file and another class file and named it as IMovie.cs and paste the below content.

Open the IMovie.cs file and add one Interface IMovie

 public interface IMovie
    {
        IList<Movie> GetMovies(string movieTitle); 
    }

and a class Movie as below
    public class Movie
    {
        public string MovieID { get; set; }
        public string Title { get; set; }
        public string Director { get; set; }
        public DateTime ReleaseDate { get; set; }
        public double Price { get; set; }           
   
    }

step 5. Compile the project and add its reference in MovieApplication Project.

step 6. Add another project class library project and named it as ComedyMovieComponent in the solution.
step 7. Add EnglishComedy.cs file and delete class1.cs file

Step 8. Add reference of MovieDetailContract assembly.

step 9. Add reference of System.Component.Composition assembly.

Step 10. Open EnglishComedy.cs file and type as below


using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MovieDetailContract;
namespace ComedyMovieComponent
{
    [Export(typeof(IMovie))]
    [ExportMetadata("MovieCategory", "EnglishComedy")]
    public class EnglishComedy : IMovie
    {
       private ICollection<Movie> MovieList()
        {
            List<Movie> movies = new List<Movie>();
            Movie comedymovie = new Movie() { MovieID = "CM1001", Title = "Sister Act", Price = 450.00 };
            movies.Add(comedymovie);
            comedymovie = new Movie() { MovieID = "CM1011", Title = "Brazil", Price = 250.00 };
            movies.Add(comedymovie);
            comedymovie = new Movie() { MovieID = "CM1010", Title = "Midnight Run", Price = 150.00 };
            movies.Add(comedymovie);
            comedymovie = new Movie() { MovieID = "CM1101", Title = "Galaxy Quest", Price = 550.00 };
            movies.Add(comedymovie);
            comedymovie = new Movie() { MovieID = "CM1401", Title = "A Fish called Wanda", Price = 450.00 };
            movies.Add(comedymovie);
            return movies;
        }

        public IList<Movie> GetMovies(string movieTitle)
        {
           
            List<Movie> movies = MovieList() as List<Movie>;
            var searchedmovies = movies.Where(m => m.Title.Contains(movieTitle)) ;
            List<Movie> movieList = searchedmovies.ToList<Movie>();
           return movieList;
        }
    }
}



You can see EnglishComedy class is decorated with Export attribute which help to plug the component in the MovieApplication socket while ExportMetadata attribute will help to dynamically finding the required component and using it for expected operation.

Step 11. Add a folder Components in the MovieApplication.


Step 12. Copy ComedyMovieComponent assembly in Components folder.

Step 13. Open Form1.cs file and add below code

 [ImportMany] 
private Lazy<IMovie, IDictionary<string, object>>[] movies { get; set; }

//This is the socket in the application where plug-in ComedyMovieComponent will fit-in. 

private CompositionContainer _container;

Step 14. Add below method to create the catalog of the components. 

 private void InitializeParts()
        {
            var catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new   DirectoryCatalog(@"D:\MEF\Mobile\MovieApplication\Components"));
            _container = new CompositionContainer(catalog);
            this._container.ComposeParts(this);

        }
reference this method in form1 constructor as below

 public Form1()        
{            
     InitializeComponent ();            
     InitializeParts();        
}

Step 15. Now add below on click event of Search button 

private void button1_Click(object sender, EventArgs e)        
{          

 RadioButton categorybutton =  groupBox1.Controls.OfType<RadioButton>().FirstOrDefault(r => r.Checked);
          string movieCategory = categorybutton.Text.Trim().Replace(" ", "").ToUpper();   
          string title = textBox1.Text.Trim();
          bool isMovieFound = false;
          foreach (Lazy<IMovie, IDictionary<string, object>> movie in movies)
          {
              string componentMovieCategory = movie.Metadata["MovieCategory"].ToString().ToUpper();
              if (componentMovieCategory == movieCategory)
              {
                  
                  List<Movie> searchedMovies = movie.Value.GetMovies(title).ToList();
                  StringBuilder movieString = new StringBuilder();
                  if (searchedMovies != null && searchedMovies.Count > 0)
                  {
                      isMovieFound = true;
                      foreach (var searchedMovie in searchedMovies)
                      {
                          movieString.AppendFormat("MovieID: {0}", searchedMovie.MovieID);
                          movieString.AppendFormat("{1}Movie Title: {0}{1} Movie Price: {2}", searchedMovie.Title, Environment.NewLine, searchedMovie.Price);
                          movieString.AppendFormat("{0}====================================={0}",Environment.NewLine);


                      }

                  }
                  richTextBox1.Text = movieString.ToString();
              }
             
          }
          if (!isMovieFound)
          {
              MessageBox.Show("Movie / Category is not available");
          }

}

Now run the application
1. Enter movie title as Braz
2. Select English Comedy radio button 
3. Click on the search button

output will come like belowAs




Now select English Adventure category and click on the Search button
Selected Movie/Category is not available message will prompt you.


English Adventure Component Development:


Now we will create English Adventure movies component and will add this to components directory of UI and this will start working.

Step 1. Add another class Library EnglishAdventureComponent in the solution
Step 2. Delete class1.cs and add EnglishAdventure class.
Step 3. Add reference of MovieDetailContract assembly.
Step 4. Add reference of System.Component.Composition assembly.
Step 5. Open the EnglishAdventure class file and add below code

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MovieDetailContract;

namespace EnglishAdventureComponent
{
    [Export(typeof(IMovie))]
    [ExportMetadata("MovieCategory", "EnglishAdventure")]
    public class EnglishAdventure:IMovie
    {

        private ICollection<Movie> MovieList()
        {
            List<Movie> movies = new List<Movie>();

            Movie comedymovie = new Movie() { MovieID = "CM1001", Title = "SpiderMan 2", Price = 450.00 };
            movies.Add(comedymovie);
            comedymovie = new Movie() { MovieID = "CM1011", Title = "SpiderMan", Price = 250.00 };
            movies.Add(comedymovie);
            comedymovie = new Movie() { MovieID = "CM1010", Title = "XMan", Price = 150.00 };
            movies.Add(comedymovie);
            comedymovie = new Movie() { MovieID = "CM1101", Title = "Avatar", Price = 550.00 };
            movies.Add(comedymovie);
            comedymovie = new Movie() { MovieID = "CM1401", Title = "Star Wars 1", Price = 450.00 };
            movies.Add(comedymovie);


            return movies;


        }

        public IList<Movie> GetMovies(string movieTitle)
        {

            List<Movie> movies = MovieList() as List<Movie>;
            var searchedmovies = movies.Where(m => m.Title.Contains(movieTitle));
            List<Movie> movieList = searchedmovies.ToList<Movie>();

            return movieList;
        }
    }

}

Step 6. Compile the project and copy the assembly from debug / bin directory and paste in the components folder of the MovieApplication.

Now I am leaving the implementation of English Drama component for you. Please email me in case of issues.

No comments:

Post a Comment