Skip to main content
 
Go Search
Home
Categories
Bloggers
By: Jeff Monnette | Posted: July 15, 2010 at 9:38 AM

FAST Search Server 2010 for SharePoint includes the capability to extend the document processing pipeline by adding additional steps. These steps are implemented as executable assemblies that accept, at minimum, two command line arguments: the path to an input file and the path to an output file. The input file is created by the document processing pipeline prior to calling the custom executable. It contains the crawled properties of the document currently being processed but is limited to those properties that are specified in the Input section of the Pipeline Extensibility configuration file. Using the input properties, the custom step executes whatever logic is necessary to generate the desired output and then writes the output to a file. The output file must contain the crawled properties that are specified in the Output section of the configuration file.

The executable runs in a sandboxed execution environment and, therefore, is limited in what resources it can access. For example, the executable cannot access any file system locations other than those passed in as the input and output paths. In my example, I will demonstrate that it is possible to connect to a SQL Server database using SQL Server authentication. However, I was not able to access the database using Windows authentication. In addition to accessing a database, the documentation from Microsoft indicates that it is possible to make web service calls from a custom step. I have not attempted to confirm this.

One challenge you will come across when trying to connect to a database or web service is how to pass in the connection information. One less than ideal approach would be to hard code this information into your assembly, but this is problematic for obvious reasons. A better approach is to use additional command line parameters and then specify the connection information in the configuration file. I will show this in my example.

Another challenge is knowing the identity under which the code will execute. I was able to confirm that the executable runs under the identity of the FAST service account. However, as I stated above, this knowledge did not do me much good since I was not able to use this identity to connect to a database or write to a file. Perhaps this identity will be more helpful in connecting to a web service.

The biggest challenge I encountered was debugging. My first thought here was to try to use the Visual Studio debugger. However, I was not able to find a way to attached the debugger to the executing process. My next thought was to write logging information to a file, but this does not appear to be possible either because of the limitations of the sandbox. I ultimately settled on writing logging information to a database table.

The only guidance I could find from Microsoft related to debugging mentioned two options. First, debug the executable outside of the document processing pipeline by creating an input file that matches the format specification. This is a great suggestion for ensuring that your logic does what you think it is supposed to do; however, it doesn't help with observing what happens inside your code when it is running in the pipeline. The second suggestion is to set an exit code other than zero and write to the standard error stream. The message you write will be visible in the SharePoint Crawl Log.

 

In the example below I will walk through the steps to create, configure, and deploy the custom processing step as well as to utilize the managed property populated by the custom step as a search result refiner. My example showcases another feature of FAST for SharePoint called entity extraction. By default, the FAST document processing pipeline will attempt to extract entities that represent company names and place names. I am going to extend this functionality by mapping the extracted company names to the location of the company's world headquarters. The company location will be stored in a new crawled property called CompanyLocation which is mapped to a new managed property also called CompanyLocation. I will use this managed property as a custom refiner on my search page.

Here are the steps to make this happen.

1) Create an executable that takes two arguments: an input file path and an output file path

I divided my code into three classes. The main Program class contains most of the logic; the DBLogger class helps with writing logging info to the database; and the CompanyLookup class gets the location value from the database. The code of all three classes is fairly straight forward so I will not explain it in detail. One thing I do want to point out, however, is the use of the \u2029 character to delimit multi-valued crawled properties. Since the companies property can have multiple companies extracted to it, I need to split on this character when reading the companies and then delimit on this character when writing to the new managed property.

using System.Linq;

using System.Text;

using System.Xml.Linq;

 

namespace FASTCompanyLookupStep

{

class Program

{

static void Main(string[] args)

{

string input = args[0];

string output = args[1];

string connection = args[2];

 

DBLogger logger = new DBLogger(connection);

 

logger.Write("This is a test to prove that I can write to a database table.");

 

XDocument inDoc = XDocument.Load(input);

 

string[] companies = inDoc.Descendants("CrawledProperty").First(e => e.Attribute("propertyName").Value == "companies").Value.Split('\u2029');

XDocument outDoc = new XDocument();

XElement docElement = new XElement("Document");

 

outDoc.Add(docElement);

 

XElement cpElement = new XElement("CrawledProperty");

docElement.Add(cpElement);

cpElement.Add(new XAttribute("propertySet", "1104E7BE-46CA-4b31-975F-4F37FB8303BE"));

cpElement.Add(new XAttribute("varType", "31"));

cpElement.Add(new XAttribute("propertyName", "CompanyLocation"));

 

StringBuilder sb = new StringBuilder();

 

CompanyLookup lookup = new CompanyLookup(connection);

foreach (string company in companies.Select(c => c.Trim().TrimEnd('\u2029')))

{

if (sb.Length > 0)

{

sb.Append('\u2029');

}

sb.Append(lookup.GetLocation(company));

}

 

cpElement.Value = sb.ToString();

 

outDoc.Save(output);

}

}

}

 

using System.Data.SqlClient;

 

namespace FASTCompanyLookupStep

{

public class CompanyLookup

{

private string ConnectionString { get; set; }

 

public CompanyLookup(string connectionString)

{

ConnectionString = connectionString;

}

 

public string GetLocation(string companyName)

{

using (SqlConnection conn = new SqlConnection(ConnectionString))

{

conn.Open();

SqlCommand cmd = new SqlCommand(string.Format("SELECT Location FROM CompanyLocation WHERE CompanyName ='{0}'", companyName));

cmd.Connection = conn;

return cmd.ExecuteScalar() as string;

}

}

}

}

using System;

using System.Data.SqlClient;

 

namespace FASTCompanyLookupStep

{

public class DBLogger

{

private string ConnectionString { get; set; }

 

public DBLogger(string connectionString)

{

ConnectionString = connectionString;

}

 

public void Write(string message)

{

using (SqlConnection conn = new SqlConnection(ConnectionString))

{

conn.Open();

SqlCommand cmd = new SqlCommand(

string.Format("INSERT INTO Logging (ProcessName, LoggedTime, [Message], UserIdentity) VALUES ('{0}', '{1}', '{2}', '{3}')",

System.Diagnostics.Process.GetCurrentProcess().ProcessName, DateTime.Now, message, Environment.UserName));

cmd.Connection = conn;

cmd.ExecuteNonQuery();

}

}

}

}

 

After compiling the assembly, you deploy to the C:\FASTSearch\bin folder on all indexing servers.

The executable will work with an input file in the format below. The file will contain the crawled properties that are specified in the configuration file. If a crawled property contains multiple values, the values will be separated by the \u2029 character. After performing the processing logic of the step, the executable will generate an output file in the same format as the input file which includes the crawled properties specified in the Output section of the configuration file.

<?xml version="1.0" encoding="utf-8"?>

<Document>

<CrawledProperty propertySet="48385c54-cdfc-4e84-8117-c95b3cf8911c" varType="31" propertyName="companies">test1test2test3</CrawledProperty>
			

</Document>

 

The executable will execute before crawled properties are mapped to managed properties.

2) Update C:\FASTSearch\etc\pipelineextensibility.xml to add your custom step to the pipeline

The next step is to update the pipeline extensibility configuration file. This needs to be done on all indexing servers. The configuration file contains a <Run> element for all custom steps that are added to the pipeline. This element includes the command line to be used to call the executable as well as the input and output crawled properties. In our example, the output crawled property will be created in the next step.

The first two command line arguments are placeholders for the input and output file paths that will be provided by the pipeline. The third argument is the database connection string that will be used for logging and lookup.

<Run command="fastcompanylookupstep.exe %(input)s %(output)s Server=(local);Database=FASTCompanyLocation;uid=Test;pwd=Test;">

<Input>

<CrawledProperty propertySet="48385c54-cdfc-4e84-8117-c95b3cf8911c" varType="31" propertyName="companies"/>

</Input>

<Output>

<CrawledProperty propertySet="1104e7be-46ca-4b31-975f-4f37fb8303be" varType="31" propertyName="CompanyLocation"/>

</Output>

</Run>

 

After updating the file, you will have to run

psctrl reset
from the command line to reset the document processors. Otherwise, the configuration changes will not take effect.

3) Run a PowerShell script from the FAST admin prompt to add new crawled properties and managed properties to the FAST configuration

The next step is to create the crawled and managed properties that will store the company locations for the document. The PowerShell script below will take care of this for you.

$guid = "1104E7BE-46CA-4b31-975F-4F37FB8303BE"

$cat = New-FASTSearchMetadataCategory -name "Custom Pipeline Properties" -propset $guid

$cp = New-FASTSearchMetadataCrawledProperty -name CompanyLocation -varianttype 31 -propset $guid

 

$mp = New-FASTSearchMetadataManagedProperty -name CompanyLocation -type 1

$mp.RefinementEnabled = $true

$mp.MergeCrawledProperties = $true

$mp.Update()

 

New-FASTSearchMetadataCrawledPropertyMapping -CrawledProperty $cp -ManagedProperty $mp    

 

4) Create a new FAST Search Center site

Next, create a FAST Search Center site in a site collection that belongs to a web application that has been configured to use FAST as its search provider. Creating the search center will give you the ability to edit the web part properties on the search results page.

5) Update the Refinement Panel web part on the search results page to include your new managed property

The last step is to update the Refinement Panel web part to include your new managed property. Adding in the <Category> element shown below will include the CompanyLoocation property as a refiner. To do this, you need to update the Filter Category Definition property under Refinement. Be sure also to uncheck the Use Default Configuration property otherwise your changes will not take effect.

<FilterCategories>  

<Category    Title="Company Location"    Description="The location of the company"    Type="Microsoft.Office.Server.Search.WebControls.ManagedPropertyFilterGenerator"    MetadataThreshold="1"    NumberOfFiltersToDisplay="4"    MaxNumberOfFilters="20"    
ShowMoreLink="True"    MappedProperty="companylocation"    MoreLinkText="show more"    LessLinkText="show fewer"    ShowCounts="Count" />
...

</FilterCategories>

 

To finish up my example, I created three Word documents in the Share Documents library to represent case studies about three different companies (Ford, Microsoft, and Starbucks). These companies also happen to be the same ones whose headquarters locations I have mapped in my database table. After running a crawl. I can execute a search on the phrase "Case Study" which is found in the title of the all three documents and my search results will include the Company Location refiner populated with the three headquarters locations.

 


			

 

One last thing to note. Your new managed property and refiner are available both via the search UI and the search web service. If you execute the following search against the web service using the QueryEx method, you will see the company location information come back as a refiner.

<QueryPacket>

<Query>

<Context>

<QueryText>Case Study</QueryText>

</Context>

<IncludeRefinementResults>

<Refiners>

<Refiner>companylocation</Refiner>

</Refiners>

</IncludeRefinementResults>

</Query>

</QueryPacket>

 

The results XML for the refiner will look something like this:

 

By: Jeff Monnette | Posted: June 21, 2010 at 10:12 AM

I just finished reading Dino Esposito and Andrea Saltarelo's book Microsoft .NET: Architecting Applications for the Enterprise. This is a great book and a must read for anyone who is architecting enterprise grade solutions on the Microsoft development platform. The book is not strictly technology specific and includes a lot of general purpose information on design principles and patters - borrowing heavily from Martin Fowler's Patterns of Enterprise Application Architecture but discusses the patterns in a .NET oriented way with .NET focused examples.

The information in this book is something that I plan to refer back to frequently when designing and building application. Rather than add new information, the purpose of this blog post is to summarize and organize the information provided by the authors to make it easier to access. I hope you find it to be a help in that way.

The book starts off with a high-level discussion of architecture and architects along with a review of UML essentials. The good stuff starts in Chapter 3: Design Principles and Patterns. Below is a summary of what I thought to be the key points from Chapter 3. I thought this would make a good checklist of high-level principles to consider when designing a solution.

Design Principles and Patterns (Chapter 3, p. 63)

Find Pertinent Objects First (p. 74)

The first key step in OOD is creating a crisp and flexible abstraction of the problem's domain. To successfully do so, you should think about things instead of processes. You should focus on the whats instead of the hows. You should stop thinking about algorithms to focus mostly on interacting entities. Interacting entities are your pertinent objects.    

Favor Low Coupling and High Cohesion (p. 68, 69, 74)

Coupling measures the level of dependency existing between to software modules, such as classes, functions, or libraries. Two modules, A and B, are said to be coupled when it turns out that you have to make changes to B every time you make any change to A.

Cohesion indicates that a given software module - be it a subroutine, class, or library - features a set of responsibilities that are strongly related. Put another way, cohesion measures the distance between the logic expressed by the various methods on a class, the various functions in a library, and the various actions accomplished by a method.

Key Points:

  • A good object-oriented design is characterized by low coupling and high cohesion.
  • A software module should focus on a single concern and the details of its implementation should be hidden behind a stable interface (modularity and information hiding).
  • Program to an interface, not an implementation.

Favor Code Reuse with Object Composition Over Class Inheritance (p. 78)

Object composition entails creating a new type that holds an instance of the base type and typically references it through a private member. In this case, you have a wrapper class that uses a type as a black box and does so through a well-defined contract. The wrapper class has no access to internal members and cannot change the behavior in any way - it uses the object as it is rather than changing it to do its will. External calls reach the wrapper class, and the wrapper class delegates the call internally to the held instance of the class it enhances. With composition, changes to the composite object don't affect the internal object. Likewise, changes to the internal object don't affect the outermost container as long as there are no changes to the public interface.

In addition to composition, another approach is frequently used to contrast class inheritance - aggregation. The difference between composition and aggregation is that with composition you have a static link between the container and contained classes. If you dispose of the container, the contained classes are also disposed of. With aggregation, the link is weaker and the container is simply associated with an external class. As a result, when the container is disposed of, the child class blissfully survives.

Open/Closed Principle (p. 80)

We need to have a mechanism that allows us to enter changes where required without breaking existing code that works. The Open/Closed Principle address exactly this issue by saying the following: A module should be open for extension but closed for modification. Applied to object-oriented design, the principle recommends that we never edit the source code of a class that works in order to implement a change. In other words, each class should be conceived to be stable and immutable and never face change - the class is closed for modification.

Today, the most common way to comply with the Open/Closed Principle is by implementing a fixed interface in any classes that we figure are subject to changes. Callers will then work against the interface as in the first principle of object-oriented design. The interface is then closed for modification. But you can make your callers interact with any class that, at a minimum, implements that interface. So the overall model is open for extension, but it still provides a fixed interface to dependent objects.

Liskov's Substitution Principle (p. 81)

The principle says the following: Subclasses should be substitutable for their base classes. It doesn't go without saying that derived classes (subclasses) can safely replace their base classes. You have to ensure that. You should handle keywords such as sealed and virtual with extreme care. Virtual (overridable) methods, for example, should never gain access to private members. Access to private members can't be replicated by overrides, which makes base and derived classes not semantically equivalent from the perspective of a caller. Generally, virtual methods of a derived class should work out of the same preconditions of corresponding parent methods. They also must guarantee at least the same post conditions.

Dependency Inversion Principle (p. 84)

High-level modules should not depend upon low-level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions. The inversion in the name of the principle refers to the fact that you proceed in a top-down manner during the implementation and focus on the work flow in high-level modules rather than focusing on the implementation of lower level modules. At this point, lower level modules can be injected directly into the high-level module.

 

Chapters 4 through 7 each focus on one of the principle layers that will found in a typical enterprise application. These chapters begin by describing the main responsibilities and characteristics of the layer and then go on to describe in detail the common design patterns used within the layer. For each pattern, I have included a reference to the page on which the pattern can be found in the book as well as a link to additional information about the pattern.

Business Logic Layer (Chapter 4, p. 129)

General Characteristics

  • The BLL consists of an array of operations to execute on some data. Data is modeled after the real entities in the problem's domain. Operations try to model business processes.
  • Typically includes an object model, business rules, services, and workflows.
  • Security in the BLL is role based and restricts access to business objects to authorized users.
  • A significant share of business rules go arm in arm with data validation. Put another way, many of the business rules are ultimately rules for validating the current content of a given business object.
  • Ideally, the percentage of business logic distributed across the presentation layer, BLL, and DAL should be 0 - 100 - 0. However, some gray areas such as data formatting, CRUD operations, and stored procedures do exist.

Transaction Script (p. 145)

Transaction Script encourages you to skip any object-oriented design and map your business components directly onto required user actions. You focus on the operations the user can accomplish through the presentation layer and write a method for each request. This method is referred to as a transaction script.

Table Module (p. 154)

Compared to TS, TM is a more structured pattern because it provides more guidance on how to do things. The simple rule for this pattern can be summarized as follows: define a business component for each database table. The business component is known as the table module class and contains all the code that operates on the given table.

Table Data Gateway (p. 164)

Used in conjunction with the Table Module pattern, the Table Data Gateway is the layer of code that retrieves a result set from the database to populate the table module and persist changes back to the database. In the .NET Framework, the DataAdapter class serves as the Table Data Gateway and a typed DataSet serves as the Table Module.

Active Record (p. 165)

Active Record is any object that wraps a record in a database table or view. The object is expected to incorporate both data and behavior. An AR object represents a row of data and typically embeds data access logic.

Foreign Key Mapping (p. 170)

An Active Record may model data that includes foreign key references to other entities. The Foreign Key Mapping pattern expands these relationships to return references to objects that represent the entities rather than the ID of the entity.

Row Data Gateway (p. 172)

The Row Data Gateway pattern delivers an object that acts as the direct interface between the wrapper AR class and the physical database. In other words, RDG will simply encapsulate all data access code for an Active Record, thus saving the Active Record class from knowing about database details.

Domain Model (p. 176)

The Domain Model pattern aims to get you an object model that is a conceptual model of the system. This object model is referred to as the domain model. The domain model describes the entities that participate in the system and captures any relationships and flow of data between them. Domain Model is totally independent of the database and is a model that is, by design, as close as possible to real processes and not an idealized model of how an architect would have processes go.

Repository (p. 188)

Use the Repository pattern to create a gateway through which code in the presentation or service layer can script the domain and update the underlying data store or load from there data that is represented through the objects in the model. Put another way, the Repository pattern adds yet another abstraction layer between the domain model and the data access code.

You typically have a repository object for each entity, such as customer, order, and product. The interface of the repository is up to you; but it will likely contain finder and update methods that work both on the single entity and on a collection of entities. Looking back on the Active Record pattern, we can say that the repository pattern offers a way to group all the CRUD methods that in Active Record belong to the entity class.

Special Case (p. 189)

The Special Case pattern recommends that you create ad hoc types that represent cases such as an entity that is not found. Rather than returning null to indicate that an entity was not found, an instance of the ad hoc type should be returned instead. This allows the method to provide a more precise answer about what happened.

 

Service Layer (Chapter 5, p. 193)

General Characteristics

  • A service layer is an additional layer that sets a boundary between two interfacing layers.
  • Orchestrates business components, application specific services, workflows, and any other special components in the business logic.
  • Typically, it shields the presentation layer from all of the details regarding the business logic.
  • Ideally, it returns DTOs and internally converts DTOs into instances of the Domain Model classes.
  • Allows, but does not require, the logic behind the service interface to be moved to a remote tier.

Service Layer (p. 205)

Addresses the need of having a common layer of simple operations for any external interface the application is required to support. The service layer contains operations that script the domain model and invoke application services in a sequence that is mostly determined by use cases. The service layer responds to input coming from the presentation layer. The presentation layer, in turn, doesn't care much about the module that operates on the other end. All that matters to it is that the module does what it claims to be able to do.

Remote Facade (p. 213)

Remote Facade refers to a particular flavor of facade - a facade for remote objects. The benefits of this facade is that it allows you to create a coarse-grained interface over a set of fine-grained objects. You need a Remote Facade when you have to refactor the service layer to a more coarse-grained interface, when you need to use explicit DTOs in the signature, or both.    

Data Transfer Object (p. 216)

A DTO is merely an object that carries data across an application's boundaries with the primary goal of minimizing roundtrips. There are two main scenarios for the DTO pattern. One is minimizing roundtrips when you call remote objects; another is maintaining a loose coupling between the front end and the classes of your domain model, if you have one.

Adapter (p. 218)

Adapter essentially converts the interface of one class into another interface that a client expects. The Adapter pattern is widely applied to render a domain object into a DTO and vice versa.

 

Data Access Layer (Chapter 6, p. 251)

General Characteristics

  • The DAL has to persist data to the physical storage and supply CRUD services to the outside world.
  • The DAL is responsible for servicing any query requests that it receives.
  • The DAL must be able to provide transactional semantics.
  • The DAL must handle concurrency properly.
  • Real database independence is achieved when you devise your DAL as a black box with a contracted interface and read the details of the current DAL implementation dynamically from configuration.

Separated Interface (p. 264)

In general terms, the Separated Interface pattern addresses the problem of separating the interface that describes a certain functionality from its implementation. The pattern prescribes that you use different packages (for example, assemblies in the .NET Framework) for the interface and any of its implementations. Only the definition of the interface is known to any assemblies that need to consume the functionality. Applied to the design of a data access layer, Separated Interface means that you define a contract for all the functionality you expose through the DAL. The contract is ultimately an interface compiled to its own assembly. The Separated Interface pattern is useful in any scenario where a given functionality of the application might be implemented through a different behavior based on runtime conditions. The DAL is just one of these cases.

Plugin (p. 267)

The Plugin pattern is described as a basic factory with some special features. In particular, the Plugin pattern suggests that you read the information about the type to create from an external configuration point. Another key point of the Plugin pattern is that the client that consumes the interface does not link the actual implementation. With regard to the DAL scenario, this means that the assembly that implements the service layer doesn't include a reference to the assembly that contains the actual DAL component. The DAL assembly, instead, is loaded in memory dynamically on demand. In the .NET Framework, this means using a pinch of reflection.

Service Locator (p. 271)

The main Service Locator focus is achieving the lowest possible coupling between components. It represents a centralized console that an application uses to obtain all the external dependencies it needs. In doing so, you also incur the pleasant side effect of making your code more flexible and extensible.

Inversion of Control (p. 273)

The basic idea behind IoC is that the consumer of some functionality doesn't bother managing dependencies itself but delegates this burden to a specialized component. The dependency injector finds the DAL implementation and makes it available to the consumer. Typically, the consumer class exposes a consutructor or a setter property through which the dependency injector can inject the references it finds.

Data Mapper (p. 281)

To persist in-memory changes, you need some mapping logic and a gateway to a DBMS-specific context. The Data Mapper pattern helps a lot here. In brief, a data mapper is the class that takes care of persistence on behalf of a given type.

Data mappers are essentially developer-created classes that fill the logical gap between the object model and the physical structure of databases.

Repository (p. 291)

Use the Repoisitory pattern to create a gateway through which code in the presentation or service layer can script the domain and update the underlying data store or load from there data that is represented through the objects in the model. Put another way, the Repository pattern adds yet another abstraction layer between the domain model and the data access code.

You typically have a repository object for each entity, such as customer, order, and product. The interface of the repository is up to you; but it will likely contain finder and update methods that work both on the single entity and on a collection of entities. Looking back on the Active Record pattern, we can say that the repository pattern offers a way to group all the CRUD methods that in Active Record belong to the entity class.

Identity Map (p. 305)

The Identity Map pattern is defined as a map that keeps track of all objects read from the database. The purpose is to return to callers an existing instance instead of running a new query. The identity map is hidden in the finder object that exposes the query services - a repository, the data context, or both. If the finder can get the requested object directly from the map, that's fine. Otherwise, it gets a reference to the object from the database and then it saves the reference into the map for further requests.

Lazy Loading (p. 315)

The Lazy Loading pattern refers to an object that doesn't hold all the data it needs, but knows how to retrieve it on demand. Applied to a domain model object, this pattern enables you to enhance the original class with the ability to prioritize data.

 

Presentation Layer (Chapter 7, p. 343)

General Characteristics

  • The presentation layer must be able to survive any changes in the graphical user interface that do not require a change in the data flow and in the presentation logic.
  • The presentation layer must also be independent from the UI technology and platform.
  • The presentation layer should be tested to some (good) extent, just like any other part of the application.
  • Whatever model you choose for the data in the middle tier, the presentation layer should be unaffected

Choosing a Pattern (p. 372)

  • Web - Stick to web forms and improve them with a bit of separation of concerns or move to a different model using ASP.NET MVC.
  • Windows - MVP is the way to go if you are looking for a presentation pattern that goes beyond the basic capabilities offered by the .NET UI toolkit of your choice - be it Windows Forms, Windows Presentation Foundation, or Silverlight.
  • Multiple GUIs - MVP is the pattern that provides the best combination of testability, separation of concerns, maintenance, and code reuse. It is possible to write a presenter and reuse it all, or in large part, in Windows and ASP.NET.

Model-View-Controller (p. 353)

The primary goal of MVC is to split the application into distinct pieces - the model, the view, and the controller. The model refers to state of the application, wraps the application's functionalities, and notifies the view of state changes. The view refers to the generation of any graphical elements displayed to the user, and it captures and handles any user gestures. The controller maps user gestures to actions on the model and selects the next view. These three actors are often referred to as the MVC triad.

Model2 (p. 362)

In a Model2 application, requests flow from the browser directly to a front controller implemented as an HTTP interceptor - in ASP.NET jargon, we would call it an HTTP module. In other words, the user interface of a Model2 application offers HTML input elements and all of them cause a link to be followed and an HTTP post to occur.

The front controller on the Web server captures the request and looks at it - in particular, it looks at the structure of the URL. based on the URL, the front controller figures out which MVC controller should be instantiated to service the request. After the controller has been identified, a method is invoked that can affect the model. As the controller's method returns, the controller orders the view to render out to HTML. The view received fresh data for its response directly from the controller.

Model-View-Presenter (p. 364)

MVP is a derivative of MVC aimed at providing a cleaner separation between the view, the model, and the controller. Starting from the MVC triad, the creators of MVP neatly separated the model from the view/controller pair, which they call presentation. The core of MVP is the strictly regulated interaction taking place between the view and the controller. In MVP, the controller is renamed to presenter.

In MVP, the view and the model are neatly separated and the view exposes a contract through which the presenter accesses the portion of the view that is dependent on the rest of the system. Summarizing the situation further, we can say that MVP is a refinement of MVC based on three facts:

  • The view doesn't know the model
  • The presenter ignores any UI technology behind the view
  • The view is mockable for testing purposes

Presentation Model (p. 370)

Presentation Model is another variation on MVP that is particularly suited to a rich and complex user interface. On the Windows platforms, PM works well with user interfaces build with Windows Presentation Foundation and Silverlight. In PM, the view doesn't expose any interface, but a data model for the view is incorporated in the model. The model is not the business logic, but simply a class that represents the state of the view. The view elements are directly bound to properties on the model. In summary, in PM the view is passive and doesn't implement any interface. The interface is transformed into a model class and incorporated into the presenter.

Page Controller (p. 372)

The traditional ASP.NET pattern requires you to use page classes as controllers. The page receives events from the view and processes them against the application logic. The page is also responsible for navigation. This traditional model can be improvbed with a deeper separation of concerns by using a manual implementation of MVC or MVP.

By: Jeff Monnette | Posted: April 19, 2010 at 6:24 PM

Extension methods in C# provide a mechanism for adding functionality to a class when you do not control the source code to that class. Most often, extension methods are used as a means of syntactically treating external utility methods as though they were methods on the class itself. In this use, the main difference between extension methods and instance methods is that extension methods do not have access to the non-public state of the object.

There has been some discussion on various blogs and forums about another use of possible extension methods. This use suggests that extension methods can be used to implement Mixins and other constructs that require a language to support multiple inheritance.

Implementing Mixins With C# Extension Methods

The discussion has included some debate about the value of using this approach vs. composition which has served as the traditional mechanism for taking advantage of multiple inheritance's benefits in a single inheritance language.

Psuedo-multiple Inheritance With Extension Methods on Interfaces in C#

I recently came across a case where I decided to utilize the extension method approach. The scenario was a refactoring of an existing codebase that included a well-entrenched object model. I needed to extract an interface and the related implementation from an existing class and then leverage both in several new classes. The class from which the interface was extracted already inherited from a base class. In an attempt to keep the refactoring as simple as possible, I decided not to change this inheritance relationship. Since I did not want to change the base class of this existing class and it did not make sense for the new classes to derive from that base class, I needed another approach for giving them a common interface and implementation.

The approach I chose for this was to extract the interface and then create a set of extension methods that extend the extracted interface. By adding this interface to the existing and new classes, I could treat them all as the same type. By utilizing extension methods, I was able to add methods to these classes that shared the same implementation. Note that in this approach, the extension methods are not part of the interface.

The alternative approach would have been to utilize composition. This would have involved including all of the common methods as part of the interface, creating a class that defines the shared implementation of these methods, and delegating to an instance of this class as the implementation of each of these methods.

Let's examine briefly the benefits and costs of each of approaches.

Extension Method Approach

The main benefit of the extension method approach is that I did not have to repeat the same code over and over in each of the classes to delegate to the class that provided the implementation of the interface methods. This saved me from writing a decent amount of code. The related benefit is that I can add additional methods to all of the classes that implement the interface simply by adding new extension methods. The interface itself and the classes do not need to change at all.

One downside to using this approach is that I need to import the namespace that contains the class that implements the extension methods into all code files that will make use of the extension methods. This would have been a headache except for the fact that the extension methods are defined within the same namespace as the interface. Because of this, I got to utilize the extension methods without any additional work.

The other major downside is that I am somewhat locked into a single implementation of each extension method for all class that share the interface.

Composition Approach

The main benefit to using the composition approach is that I would have the freedom to provide alternative implementations for the interface methods either by coding directly within the classes that implement the interface, by delegating to a different class, or by delegating to a different method on the same class. This would provide me with a great deal more flexibility down the road.

I think the only real downside to this approach is the added coding effort that I mentioned above.

 

In summary, the composition approach appears to be the better of the two if you are looking for the most flexible option and anticipate a need to provide alternative implementations for different classes. On the other hand, the extension method approach can be a viable alternative if you anticipate that the implementation of the methods will remain the same for all classes that share the interface and you value the benefit of writing less code (i.e., you have a large number of classes sharing the interface).

Of course, it is possible to start with the extension method approach and then refactor to use the composition approach at a later date if it becomes desirable to do so.

Ideally, you could avoid the need to use either of these approaches by identifying upfront a design that would allow this shared functionality to be placed in a common base class. However, it is not always possible to anticipate this type of requirement as your system may evolve over time to include unanticipated uses. Also, there are likely to be many scenarios in which classes that require shared functionality should not share a common base class. In such cases, composition would appear to be the better alternative due to the flexibility that it provides in making future changes. In cases where you are refactoring to add an interface to a large number of classes that cannot share a common base class, the extension method approach can be a viable alternative that leaves room to switch to composition later if needed.

 

By: Jeff Monnette | Posted: April 19, 2010 at 6:20 PM

 

By default, SharePoint uses URLs like the following for the page that displays a post on a blog site:

http://blogs.mycompany.com/blogs/blogger_name/lists/posts/post.aspx?ID=1

With a little code in an HTTP Module, we can support a much more user friendly URL format for displaying posts. In this example, I will show you how to create a module that implements URL rewriting and response filtering to support URLs that look like this instead:

http://blogs.mycompany.com/blogs/blogger_name/1/blog_post_title

Not only is this format more friendly to users but it can also increase your search engine page ranking by including keywords from the post title in the URL.

To achieve this, we will create a module that accomplishes two things: 1) filter all responses in the blogs site to modify any hyperlinks to the Post.aspx to use the user-friendly URL instead; 2) rewrite requests for the user-friendly URLs into a format that ASP.NET can use to pass the request off to the Post.aspx page.

Below is the code of the module. All the module itself does is set up the URL patterns that need to be processed by the module and then hook into the BeginRequest event to determine whether or not the current request matches one of the configured routes. If it does, the we execute the HandleRoute method on the matched route.

All of the work of matching the current request to a route is done by the System.Web.Routing.RouteCollection class when we call GetRouteData. All we have to do is set up the routes by specifying a matching pattern and providing an implementation of IRouteHandler. The real work of the module is done within the IRouteHandler implementations that we delegate to when we call HandleRoute.

Now we will examine how to implement the response filtering and URL rewriting. For the first, I've created a class called BaseHandler that implements IRouteHandler. Note that we've implemented IRouteHandler so that we can use the RouteData class as a convenient storage place for our route handler. We do not actually need the functionality provided by the interface.

Inside this HandleRoute method of this class, we modify the response to ensure that it is buffered and then set up a filter to handle making the changes to the URLs in any hyperlinks on the page. This filter will parse the response and modify it as needed before ASP.NET sends it to the browser.

This parsing and fixing is done in the UrlFixupFilter class. This class is an implementation of Stream that simply delegates to the Stream that was passed into the constructor for all methods except for Write. In Write, we make our modifications to the buffered content before delegating to the Write method of the underlying stream.

The code to make the modifications is found in the replaceUrls method. This method utilizes a regular expression to find and replace the href attribute of any hyperlinks to the Post.aspx page. After this code executes, these hyperlinks will point to the user-friendly URL instead.

One additional note on this code, I added a check at line 133 to prevent modification to the Permalink hyperlink that SharePoint renders for blog posts.

Last, we'll take a look at the route handler that handlers the requests to the user-friendly URLs. This handler simply rewrites the URL to Post.aspx and appends the post ID to the query string using the value passed-in via the RouteData object.

By deploying this module to our SharePoint application, we can utilize URLs that are much more user-friendly, and search-engine-friendly as well, while still leveraging all of SharePoint's out of the box blog functionality.

In this post, we examined two very powerful mechanisms for enhancing SharePoint or ASP.NET applications. First, URL rewriting allows us to support friendly URLs within our applications. These URLs need not point to the .aspx file that will ultimately handle the request. Instead our module provides a mapping layer that routes requests to the .aspx file without the knowledge of the user. Second, we utilized post-processing on the response to filter out the ugly old URLs in hyperlinks and replace them with our clean, friendly URLs before the response is sent to the browser. In doing this, we leveraged the System.Web.Routing namespace which was introduced to ASP.NET for use in the MVC Framework but provides us with lots of useful capabilities in our non-MVC applications as well.

Some potential enhancements that could be explored include 1) making the module more configurable so that it is not coupled tightly to the URL structure hardcoded into the Route definitions; 2) adding routes to provide friendly URLs for the Category.aspx page; and 3) updating the filter class so that it does its URL modification based on data defined in the RouteCollection instead of using hardcoded strings.

By: Jeff Monnette | Posted: November 9, 2009 at 4:18 PM

I just returned from the 5 day SharePoint 2010 Ignite Training for Developers in Amsterdam. The training was an invitation-only opportunity for Mircrosoft's top-tier partners to get hands-on experience with the latest and greatest features in the upcoming SharePoint release. I feel very fortunate to have had the opportunity to go to this event and to have had such an in-depth look at what should prove to be one of Microsoft's most exciting product releases ever. We learned about the many new features that will make the SharePoint platform an easier and richer experience for both developers and users. I'll give you a brief overview of some of my favorites.

 

Visual Studio Tools

Visual Studio 2010 includes templates for creating all kinds of SharePoint items including list definitions, workflows, web parts, and event receivers. SharePoint project templates include integrated support with visual designers for feature and WSP creation. When adding a new SharePoint item such as a list definition or web part, Visual Studio will automatically create the feature definition needed to deploy the item.


Mapped Folders allow items to be added to folders that map to the RootFiles folder structure (now the 14 hive). When added to your Visual Studio project, any files placed within these folders will be included in the WSP generated by the project and deployed to the mapped folder under the 14 hive.

Visual Studio 2010 also includes the ability to manage WSP deployment automatically from within the build process. When the project is created, it can be associated with a SharePoint site for development purposes. After this is done, the solution can be deployed directly from Visual Studio making it easy to debug using the Visual Studio debugger. The F5 debugging experience for a SharePoint project does the following:

  1. Builds the DLLs and the WSP
  2. Deactivates and uninstalls the features
  3. Retracts the old WSP
  4. Adds and deploys the new WSP
  5. Activates the features in the associated site
  6. Attaches the debugger to the W3WP process for the associated site

The SharePoint Explorer window within Visual Studio gives easy access to artifacts within a SharePoint site running locally.

Best of all, these tools within Visual Studio are highly extensible and customizable. You can create your own SharePoint item templates, develop custom visual designers, and extend the SharePoint Explorer window with additional nodes and information.

 

Other Developer Tools

Another really useful tool to help with debugging is the SharePoint Developer Dashboard. When enabled on your site, this tool provides some excellent debugging and diagnostic information about the execution of web parts on the page.

SharePoint Designer enhancements make it a useful tool not only for power users, but also for developers. There is now tighter integration between work done in SharePoint Designer and Visual Studio. Items such as workflows, content types, lists, and pages can be prototyped in SharePoint Designer, exported to a WSP and then imported into Visual Studio to be integrated with other project artifacts and source control.

SharePoint Designer also provides a powerful interface for working with Business Connectivity Services (formerly known as the Business Data Catalog) and creating External Content Types and Lists. See my previous blog post for a detailed look at this new capability.

As I wrote in previous posts, PowerShell will become an indispensible tool for both developers and administrators. PowerShell cmdlets will replace STSADM as the preferred admin shell for SharePoint and the ability to write custom cmdlets will make it easy to automate all kinds of tasks. For more details, check out my posts on SharePoint 2010 and PowerShell and accessing the object model with PowerShell.

 

Feature and Solution Improvements

In addition to the direct integration with Visual Studio for creating features and solutions, there are many other improvements to the feature/solution framework that will make it more powerful and easier to work with. First among these is the new type of solution called a Sandboxed Solution that allows solutions to be deployed in an isolated manner that prevents custom code from accessing resources that could cause damage to the farm. Other new capabilities at the solution-level include solution activation dependencies, application resource files, and solution versioning.

In the feature framework, new capabilities include versioning, declarative upgrade actions, and a hookable feature upgrade event; feature-level solution activation dependencies, and new events including web provisioning and workflow events.

 

UI Enhancements

The out-of-the-box SharePoint UI has been completely overhauled to take advantage of AJAX capabilities to improve the user experience by eliminating a great deal of the post-back and navigation that was necessary to perform common tasks within SharePoint 2007. The new UI also introduces the ribbon concept from Office 2007 to consolidate commands into one location and present the user with the most relevant commands for the current context. Most important from a developer perspective, the ribbon and list dialogs can be customized with additional commands and information. Also the AJAX dialogs can be leveraged to provide custom capabilities in a manner consistent with out-of-the-box features.

Perhaps the most exciting change to the UI is the new level of standards compliance. The platform will now emit well-formed XHTML and provides better support for Firefox and Safari.

To support these improvements, the CSS and master pages have been completely overhauled and SharePoint now includes simple and minimal master pages to assist with custom development.

 

LINQ to SharePoint

Probably my favorite new feature is the direct integration of LINQ to SharePoint into the platform. The CodePlex project has become part of the platform itself and a new RESTful web service has been added to support access to list data via ADO.NET Data Services. These new features will make it easier to get at list data in a concise and efficient manner whether you are on the server, in an AJAX application, or in a .NET thick-client.

The main benefit of LINQ to SharePoint is that it allows developers to write efficient queries against SharePoint lists without the need to write CAML. Developers write their queries in LINQ and the LINQ to SharePoint provider translates them into CAML before retrieving the data from the list. This is a huge benefit to those of us who like prefer the simple, clear, and consistent LINQ syntax to the verbose XML of CAML.

The RESTful ListData.svc service is a major upgrade over Lists.asmx. Rather than crafting complex CAML to query the service and then parsing a messy XML result set as was done with Lists.asmx, we can now retrieve list data via simple URL/query string syntax and have the results sent back either formatted either as Atom or JSON. Check out my recent blog post for more information on ListData.svc.

 

Client Object Model

When your client-side needs go beyond list data, the new client object model provides access to a significant portion of the SharePoint API from .NET, Silverlight, and JavaScript clients running off-server. Each of these clients is supported by its own class library.

Client Type

Library

.NET

Microsoft.SharePoint.Client.dll

Silverlight

Microsoft.SharePoint.Client.Silverlight.dll

JavaScript

Layouts/SP.js

 

The classes in these libraries mirror various classes within the Microsoft.SharePoint assembly.

Server-side Class

Client-side Class

SPContext

ClientContext

SPSite

Site

SPWeb

Web

SPList

List

SPListItem

ListItem

SPField

Field

 

The client-side classes encapsulate calls to the Client.svc web service which in turn utilizes the server-side object model to execute the requested update or query. The web service then sends back a response with the return value formatted as JSON.

 

As you can see, there is a lot for developers to get excited about in SharePoint 2010. Have fun playing around with these new features in the beta and getting ready for the release next year.

 

 About Jeff Monnette

Managing ConsultantJeff Monnette is a managing consultant for PointBridge.  He has over 8 years of experience in IT and business consulting for clients in a wide range of industries including financial services, energy ... [more]
MCPD
MCTS

 Tag Cloud

 External Links

 ‭(Hidden)‬ Admin Links