|
|||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThis article is the second part in the series: Building a Web Message Board using Visual Studio 2008. The first part in the series can be accessed here: Contents
Visual Studio 2008 Features Demonstrated in this ArticleThis article demonstrates the following features of Visual Studio 2008:-
Let's get started by looking at what we build in the article, and then we can see the steps involved in building it. Posting Messages using Microsoft WordIn this article, we will be building a Microsoft Word document template. Users can create Word documents using this template. The Word document, so created, will have place holders where the user can type in a message subject and a message text. Once the user is done with typing the message, he can click on a ribbon button labeled Post Message. This causes the message to be posted on the MessageBoard website. The following screenshot demonstrates all the components: The Post Message ribbon button is only available for documents developed using the custom document template. Any other Word document will appear in the normal fashion, i.e., it will not have the Post Message button. Before proceeding, let's look at the reasons why we are going through the trouble of building a custom Word document template. Why use Microsoft Word?It has happened to me many times that I prepare an elaborate post for a message board, such as that in the CodeProject website or the www.asp.net website, and I accidentally close the browser, or get disconnected from the internet, or accidentally navigate to a different site. The elaborate message I prepared gets lost, and I have to either re-type the entire thing or not post the particular message. So, the solution I adopted (and which many other people have adopted) is that I type the message separately in Word or Notepad and then copy and paste the message text to the appropriate form fields in the message posting page. Then I submit the form to the website. The advantage of using Word is that I can save the message offline and also get all the good features such as spelling and grammar correction. The code presented in this article provides the users with a custom document template that they can use to post a message to the MessageBoard website developed in the previous article. The users can directly post the message from Word, and they don't have to cut and paste the message contents to form fields in a web page.
Before we get started with actual code, let's look at the different types of Microsoft Office Word solutions we can develop in Visual Studio 2008. Developing Microsoft Word Solutions in Visual Studio 2008Microsoft Office Word is a highly customizable application. VBA (Visual Basic for Applications) was available to Office Developers for a long time. VBA allowed developers to automate certain tasks in Microsoft Word such as formatting ranges, customized search and replace etc. The VBA code was saved with Microsoft Word documents or the templates. VBA macros only worked for a particular document or a template. For application level customization, Word has support for Add-Ins. Word Add-ins can be COM based, hence can be developed in Visual C++, Visual Basic 6.0, or even Managed code. Visual Studio Tools for Office (VSTO) provides an easier, better, and secured way to create Word solutions in managed code. The VSTO runtime shields most of the COM details, and provides a more .NETish way to develop Word solutions. Also, VSTO solutions run in a separate app-domain, and therefore they provide a good degree of isolation among different solutions. VSTO has support for the following:
Now that we have seen different solutions that can be created using VSTO, let's select the right solution for the message board application. Selecting the Right SolutionFor the message board application, we can theoretically use any of the three types of solutions supported by VSTO. We can build an add-in that allows documents to be posted to the message board. However, the problem with an add-in is that it will be available for all the documents. The format of the document we want to use to post to the message board is mostly fixed: it has an area where the user can type the subject and an area where the user can type in the message text. Thus, it does not make much sense to develop an application level add-in. We can either develop a customized Word document or a document template. The customized document template makes more sense for the following reason:
Now that we have decided to use a document template, let's get our hands dirty with some coding and jump right into development. Getting Started with the Word 2007 TemplateIn this article, I will be working with Word 2007. The procedure for developing a Word 2003 template will differ slightly. The main difference is that Word 2003 does not use ribbons. Depending on the requirements in a real project, you may have to support both Word 2003 and Word 2007. If you are interested in learning how to develop for multiple versions of Word, please leave a comment. To start, download the code from Part I of the article, by clicking on this link, and follow the installation instructions to install the back-end database. Next, extract the zip file and open the MessageBoard.sln file in Visual Studio. Right click on the solution, and click on Add New project. From the project dialog box, select: This will cause the VSTO Wizard to appear: Type MessageBoard as the name of the document (as shown), and click OK. This will cause Word to open within the Visual Studio window, as shown below: You can drag and drop controls from the tool box to the Word document. Next, we will add controls to the Word document. Adding Word Controls to the TemplateYou can drag and drop and use most of the Windows Forms controls in a Word document. In this project, however, we will be using a special type of controls called Word controls: These controls are also called content controls. Content controls can be used to develop form like input within a Word document. Content controls can be used to designate different areas in the Word document for a specific purpose. For example, in the message board document template, we want to designate an area for entering the message subject and the message text. The control we will use is the
Here is how the properties are set for the We also format the Here is how the properties look like for the Now that we have designated areas in the document for subject and text, we need to provide a means to the end user by which he can post the text entered in the content controls to the message board. In Office 2007, a user invokes commands using the Ribbon. In the next section, we will add controls to the Ribbon so that the user can post messages. Adding Controls to the RibbonPrior to Visual Studio 2008, adding controls to the Ribbon was done by hand editing XML files. Visual Studio 2008 includes a graphical designer for designing Ribbon controls.
To add a Ribbon, right click on the project and select Add Item. Select Ribbon from the list of items, as shown below: The Ribbon appears in the designer as shown below: The Ribbon tab consists of Ribbon groups, and each Ribbon group consists of Ribbon controls, as shown. Microsoft Word has predefined Ribbon tabs such as Home, Insert, Page Layout, Add-ins etc. The Ribbon created using the designer in the above screenshot will merge with the existing controls in the pre-existing Ribbon tab named Add-Ins. However, in our message board sample, we want the control to appear in the Home tab. To do so, we need to modify the properties of the tab. Click on the ribbon tab in the designer, and modify the properties as shown below: We changed the Now, if you run the application, the ribbon group will correctly appear in the Home tab; it will, however, appear at the extreme right. In order to make it appear in the left, we have to modify the properties of the group as shown: The important property to note here is the Now, we have the ribbon group appearing in the correct tab at the correct position. Next, we need to add a button to the group. You can add a button to the ribbon by dragging and dropping a A button in the ribbon has text, an ID, and an icon image. You can either specify a custom icon image for a button, or use some standard images which ship with Office. The list of standard office image IDs is available in an Excel worksheet available here. In the case of the message board, I use the same icon that the default blog template uses for posting a message. The icon ID is Now that we have a button, we can add code to handle its private void post_Click(object sender, RibbonControlEventArgs e)
{
Globals.ThisDocument.PostMessage();
}
The internal void PostMessage()
{
if (!ValidateSubjectAndText())
return;
//if (!AuthenticateUser())
// return;
//InvokeWebService();
}
We first validate the subject and the text to make sure that they are not empty. If the validation is successful, we call a method called private bool ValidateSubjectAndText()
{
//Validate the subject
if (String.IsNullOrEmpty(subject.Text))
{
MessageBox.Show(Resources.SpecifySubject, Resources.ApplicationName);
return false;
}
//Validate the text
if (String.IsNullOrEmpty(messageText.Text))
{
MessageBox.Show(Resources.SpecifySubject, Resources.ApplicationName);
return false;
}
return true;
}
We have not yet added the actual code to post the message to the message board. Before we do that, we need to expose the message board API as a web service. This web service can then be used by the document template to post the message. Now, let's move on to the server side. Creating the Message Board Web ServiceWe need to add a web service that can be used by the document template project to add messages to the message board. To add a message to the message board, we use the public static void AddMessage(string subject, string text)
The details of the method are in the previous article in the series. We have to expose a web service that, in turn, uses this method to add the message to the message board. The first question is what kind of web service should we create? We have two options: ASP.NET (asmx) web services or WCF Web services. In the next section, we will decide which one to use. To WCF or to ASMX?Prior to WCF, ASP.NET Web services (asmx) was the common way web services were built in .NET. ASP.NET Web Services are not as rich as WCF. For instance, WCF has support for most of the WS Specs. The neat thing about WCF is that you can get rich web service features just by changing the configuration file. Although we will not be using a lot of WCF features in this article, it still makes sense to expose the message board as a WCF service as it will be easy to to have a rich web service support in the future. In the next section, we will create the WCF service. Creating the WCF ServiceFollowing the conventions of the previous article, we will add the actual code for the WCF service in the MessageBoard.Web project and add the svc file that exposes the web service to the MessageBoard website. The easiest way to create a web service is to use the Add New Item dialog box: This automatically creates the Service contract - [ServiceContract]
public interface IMessageBoardService
{
[OperationContract]
void AddMessage(string subject, string text);
}
Next, we need to modify the [AspNetCompatibilityRequirements(RequirementsMode
=AspNetCompatibilityRequirementsMode.Allowed)]
public class MessageBoardService : IMessageBoardService
{
public void AddMessage(string subject, string text)
{
MessageSource.AddMessage(subject, text);
}
}
Notice, the <system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
Combined together, these properties ensure that the The next step is to add an svc file which will be used to access the WCF service. We create a file named MessageBoard.svc in the MessageBoard website: <%@ ServiceHost Service="MessageBoard.Web.MessageBoardService" %>
The easiest way to do it is to add a text file to the website and rename the extension to svc. We are not fully done with the web service yet. We need to add configuration settings to the web.config file. Configuring the ServiceWCF services need to be configured before they can be used. You can either use the WCF Service Configuration Editor, or hand edit the web.config file. Either way, you need to add the following settings to the configuration file: <system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<serviceBehaviors>
<behavior name="MessageBoardServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MessageBoardServiceBehavior"
name="MessageBoard.Web.MessageBoardService">
<endpoint binding="basicHttpBinding"
bindingConfiguration=""
contract="MessageBoard.Web.IMessageBoardService" />
</service>
</services>
</system.serviceModel>
We are exposing the service using Now, let's go back to the document template project and see how we can invoke the web service. Linking Server and ClientIn order for us to invoke the web service from the client project, we need to add a reference to the web service. This can be done by right clicking on the MessageBoard.Word project and selecting Add Service Reference. In the Add Service Reference dialog box that shows up, click on the Advanced button on the lower left corner. In the dialog box that pops up, click the Add Web Reference button. This will bring up the Add Web Reference dialog box. In the resulting dialog box, click on web services in the current solution and select the MessageBoardService. Once you select the MessageBoardService, the proxy class to invoke the service is automatically created for you.
Now, we are ready to invoke the web service. Invoking the Web ServiceWe added a place holder method named private void InvokeWebService()
{
using (MessageBoardService service = new MessageBoardService())
{
try
{
service.AddMessage(subject.Text, messageText.Text);
MessageBox.Show(Resources.MessagePosted,
Resources.ApplicationName);
}
catch (WebException ex)
{
MessageBox.Show(ex.Message, Resources.ApplicationName);
}
catch (SoapException ex)
{
MessageBox.Show(ex.Message,
Resources.ApplicationName);
}
}
}
Uncomment the internal void PostMessage()
{
if (!ValidateSubjectAndText())
return;
//if (!AuthenticateUser())
// return;
InvokeWebService();
}
To test launch the MessageBoard.Web project, enter some subject and text, and click on the Post Message button in the ribbon. If the message is posted successfully, you will get a message box indicating that the message was posted successfully. You can also view the message board website in the browser to make sure that the message appears. If everything worked correctly, you will notice that new messages are posted anonymously. That is the case because we have not yet authenticated the users. In the next section, we will use ASP.NET client application services to authenticate the user. Using ASP.NET Client Services to Authenticate the UserIf you have been using WCF, you might be wondering why we are not using the WCF authentication in this article. WCF security is quite powerful, and it also integrates with ASP.NET membership. However, WCF authentication requires extra configuration work. For example, if you want to use user name/password authentication in WCF, you need to configure a certificate (or a test certificate) in order to make the authentication work. Although such high security may be needed for many projects, I decided to keep things simple and use a light weight alternative: ASP.NET Client Application Services. What are the ASP.NET Client Application Services? Put simply, ASP.NET Client Application Services allow you to access the membership, profile and roles services on an ASP.NET web server remotely from any .NET application. So, if you have a web server configured with ASP.NET membership, you can use the web server to authenticate a user on a desktop Windows application. This is an extremely lightweight API for authentication. If you recall, the MessageBoard site was configured with ASP.NET membership, and users were authenticated using ASP.NET membership. Now, we need to do the same for the messages posted from Microsoft Word. To achieve authentication using ASP.NET membership, first, we need to configure the server. Add the following settings to the web.config file: <system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true"/>
</webServices>
</scripting>
</system.web.extensions>
Next, we need to modify the project properties of the MessageBoard.Web project: Under the Authentication service location, enter the URL of the MessageBoard website. Also notice the Credentials provider field set to public partial class LogOnForm : Form,
IClientFormsAuthenticationCredentialsProvider
{
public LogOnForm()
{
InitializeComponent();
}
public ClientFormsAuthenticationCredentials GetCredentials()
{
return (this.ShowDialog() == DialogResult.OK) ?
new ClientFormsAuthenticationCredentials(
userName.Text,
password.Text,
rememberMe.Checked)
: null;
}
}
Here is how the form looks in the designer: When you authenticate the user using the Client Application Services, this dialog box will automatically be shown when the user name supplied to the authentication API is null or empty and if there are no saved credentials. The client application service automatically saves the user credentials in an offline SQL Server Everywhere database when indicated to do so (Remember Me is checked). The database is automatically created by default in the user's data directory. If you don't intend to save the user authentication data, you can do so by clicking the Advanced button in the Services page in the project properties. Now, let's see the steps involved in authenticating the user. Once the project properties have been set correctly, authenticating the user is as simple as calling the private bool AuthenticateUser()
{
//Authenticate the user
if (!Membership.ValidateUser(String.Empty,
String.Empty))
{
if (MessageBox.Show(
Resources.InvalidUserNamePassword,
Resources.ApplicationName,
MessageBoxButtons.YesNo)
!= DialogResult.Yes)
return false;
}
return true;
}
The We are not done yet. We need to make sure that the web service is invoked with the authentication done by the using (MessageBoardService service = new MessageBoardService())
{
ClientFormsIdentity identity =
Thread.CurrentPrincipal.Identity as ClientFormsIdentity;
//Make sure that the authentication cookies go with the web request
if (identity != null)
service.CookieContainer = identity.AuthenticationCookies;
try
{
service.AddMessage(subject.Text, messageText.Text);
MessageBox.Show(Resources.MessagePosted,
Resources.ApplicationName);
}
catch (WebException ex)
{
MessageBox.Show(ex.Message,
Resources.ApplicationName);
}
catch (SoapException ex)
{
MessageBox.Show(ex.Message,
Resources.ApplicationName);
}
}
If the authentication succeeds, the This concludes the second part in the article series. In the next part, we will go back to the website and add some AJAX support. Please be free to leave comments about the article, especially if you think that the article is lacking. That will help me improve future articles. Series NavigationHistory
| ||||||||||||||||||||||||||||