http://msdn.microsoft.com/en-us/library/aa192483(office.11).aspx

 Word.Table tbl = ThisDocument.Tables[1];
tbl.Range.Font.Size = 8;
tbl.Range.Font.Name = “Verdana”;

Object style = “Table Grid 8″;
tbl.set_Style(ref style);
tbl.ApplyStyleFirstColumn = false;
tbl.ApplyStyleLastColumn = false;
tbl.ApplyStyleLastRow = false;

// Insert header text and format the columns.
tbl.Cell(1, 1).Range.Text = “Name”;

Word.Range rngCell;
rngCell = tbl.Cell(1, 2).Range;
rngCell.Text = “Size”;
rngCell.ParagraphFormat.Alignment = 
    Word.WdParagraphAlignment.wdAlignParagraphRight;

rngCell = tbl.Cell(1, 3).Range;
rngCell.Text = “Modified”;
rngCell.ParagraphFormat.Alignment =
    Word.WdParagraphAlignment.wdAlignParagraphRight;

http://www.c-sharpcorner.com/UploadFile/amrish_deep/WordAutomation05102007223934PM/WordAutomation.aspx

7. Embedding a Document:

Embedding a document is done through the application by

Insert-> Object-> Create from file-> Select the File-> Display as Icon. This embeds the file in the selected location as an icon and the user can double click on the icon to open the file. The same can be done through automation.

The range supposed to set at the required place and the same has to be selected (range can be set by any of the means mentioned above). Now with the selection, the file can be embedded.

//ICON LABEL CAN BE THE NAME OF THE FILE,

//ITS THE NAME DISPLAYED BESIDES THE EMBEDDED DOCUMENT

Object oIconLabel = “File Name”;

//INCASE WE NEED THE EMBEDDED DOCUMENT TO BE DISPLAYED AS A SPECIFIC ICON,

//WE NEED TO SPECIFY THE LOCATION OF THE ICON FILE

//ELSE SET IT TO oMissing VALUE

Object oIconFileName = “C:\\Document and Settings\\IconFile.ico”;

//THE BOOKMARK WHERE THE FILE NEEDS TO BE EMBEDDED

Object oBookMark = “My_Custom_BookMark”;

//THE LOCATION OF THE FILE

Object oFileDesignInfo = “C:\\Document and Settings\\somefile.doc”;

//OTHER VARIABLES

Object oClassType = “Word.Document.8″;

Object oTrue = true;

Object oFalse = false;

Object oMissing = System.Reflection.Missing.Value;

//METHOD TO EMBED THE DOCUMENT

oWordDoc.Bookmarks.get_Item(ref oBookMark).Range.InlineShapes.AddOLEObject(

ref oClassType,ref oFileDesignInfo,ref oFalse, ref oTrue, ref oIconFileName,

ref oMissing,ref oIconLabel, ref oMissing);

http://www.codeproject.com/KB/cs/Three_Layer_Architecture.aspx

Introduction

Here in this article, I would like to cover the typical three layer architecture in C# .NET. It is a very useful approach for coding due to easy code maintenance.

Overview

First let me give you a small overview about the topic I would like to cover in this article.

  1. Tier vs. Layer
  2. Three Tier/Layer Architecture Design Components
  3. Demo: Three Layer Windows Application in C#.NET

1. Tier vs. Layer

1.1 Tier: Tier indicates a physical separation of components, which may mean different assemblies such as DLL, EXE, etc. on the same server or multiple servers.

As you can see in the above figure, Data Tier have no direction with Presentation Tier, but there is an intermediate Tier called Business Tier which is mainly responsible to pass the data from Data Tier to Presentation Tier and to add defined business logic to Data.

So, if we separate each Tier by its functionality, then we come to know the below conclusion:

1.2 Layer: Layer indicates logical separation of components, such as having distinct namespaces and classes for the Database Access Layer, Business Logic Layer and User Interface Layer.

2. Three Tier/Layer Architecture Design Components

As we have already seen, tier is the sum of all the physical components. We can separate the three tiers as Data Tier, Business Tier and Presentation Tier.

  • Data Tier is basically the server which stores all the application’s data. Data tier contents Database Tables, XML Files and other means of storing Application Data.
  • Business Tier is mainly working as the bridge between Data Tier and Presentation Tier. All the Data passes through the Business Tier before passing to the presentation Tier. Business Tier is the sum of Business Logic Layer, Data Access Layer and Value Object and other components used to add business logic.
  • Presentation Tier is the tier in which the users interact with an application. Presentation Tier contents Shared UI code, Code Behind and Designers used to represent information to user.

The above figure is a mixture of Three Tier and Three Layer Architecture. Here, we can clearly see a different between Tier and Layer. Since each component is independent of each other, they are easily maintainable without changing the whole code.

This approach is really very important when several developers are working on the same project and some module needs to be re-used in another project. In a way, we can distribute work among developers and also maintain it in the future without much problems.

Testing is also a very important issue for Architecture when we are considering writing a test case for the project. Since it’s like a modular architecture, it’s very handy testing each module and to trace out bugs without going through the entire code.

3. Demo: 3 Layer Windows Application in C#.NET

Let’s go though from one module to other to have a better understanding of it.

dbConnection

This class is mainly used to do the database activity like Select, Update and Delete query to database. It also checks if the database connection is open or not. If database connection is not open, then it opens the connection and performs the database query. The database results are to be received and being passing in Data Table in this class.

This class takes the database setting from the app.config file so it’s really flexible to manage the database settings.

Collapse Copy Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;

namespace ThreeLayerDemo.Core
{
    public class dbConnection
    {
        private SqlDataAdapter myAdapter;
        private SqlConnection conn;

        /// <constructor>
        /// Initialise Connection
        /// </constructor>
        public dbConnection()
        {
            myAdapter = new SqlDataAdapter();
            conn = new SqlConnection(ConfigurationManager.ConnectionStrings
					["dbConnectionString"].ConnectionString);
        }

        /// <method>
        /// Open Database Connection if Closed or Broken
        /// </method>
        private SqlConnection openConnection()
        {
            if (conn.State == ConnectionState.Closed || conn.State ==
						ConnectionState.Broken)
            {
                conn.Open();
            }
            return conn;
        }

        /// <method>
        /// Select Query
        /// </method>
        public DataTable executeSelectQuery(String _query, SqlParameter[] sqlParameter)
        {
            SqlCommand myCommand = new SqlCommand();
            DataTable dataTable = new DataTable();
            dataTable = null;
            DataSet ds = new DataSet();
            try
            {
                myCommand.Connection = openConnection();
                myCommand.CommandText = _query;
                myCommand.Parameters.AddRange(sqlParameter);
                myCommand.ExecuteNonQuery();
                myAdapter.SelectCommand = myCommand;
                myAdapter.Fill(ds);
                dataTable = ds.Tables[0];
            }
            catch (SqlException e)
            {
                Console.Write("Error - Connection.executeSelectQuery - Query:
			" + _query + " \nException: " + e.StackTrace.ToString());
                return null;
            }
            finally
            {

            }
            return dataTable;
        }

        /// <method>
        /// Insert Query
        /// </method>
        public bool executeInsertQuery(String _query, SqlParameter[] sqlParameter)
        {
            SqlCommand myCommand = new SqlCommand();
            try
            {
                myCommand.Connection = openConnection();
                myCommand.CommandText = _query;
                myCommand.Parameters.AddRange(sqlParameter);
                myAdapter.InsertCommand = myCommand;
                myCommand.ExecuteNonQuery();
            }
            catch (SqlException e)
            {
                Console.Write("Error - Connection.executeInsertQuery - Query:
			" + _query + " \nException: \n" + e.StackTrace.ToString());
                return false;
            }
            finally
            {
            }
            return true;
        }

        /// <method>
        /// Update Query
        /// </method>
        public bool executeUpdateQuery(String _query, SqlParameter[] sqlParameter)
        {
            SqlCommand myCommand = new SqlCommand();
            try
            {
                myCommand.Connection = openConnection();
                myCommand.CommandText = _query;
                myCommand.Parameters.AddRange(sqlParameter);
                myAdapter.UpdateCommand = myCommand;
                myCommand.ExecuteNonQuery();
            }
            catch (SqlException e)
            {
                Console.Write("Error - Connection.executeUpdateQuery - Query:
			" + _query + " \nException: " + e.StackTrace.ToString());
                return false;
            }
            finally
            {
            }
            return true;
        }
    }
}

Database Access Layer

Database Access Layer (DAO) builds the query based on received parameters from the Business Logic Layer and passes it the dbConnection class for execution. And simple return results from the dbConnection class to Business Logic Layer.

Collapse Copy Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace ThreeLayerDemo.Core
{
    public class UserDAO
    {
        private dbConnection conn;

        /// <constructor>
        /// Constructor UserDAO
        /// </constructor>
        public UserDAO()
        {
            conn = new dbConnection();
        }

        /// <method>
        /// Get User Email By Firstname or Lastname and return DataTable
        /// </method>
        public DataTable searchByName(string _username)
        {
            string query = string.Format("select * from [t01_user]
		where t01_firstname like @t01_firstname or t01_lastname
		like @t01_lastname ");
            SqlParameter[] sqlParameters = new SqlParameter[2];
            sqlParameters[0] = new SqlParameter("@t01_firstname", SqlDbType.VarChar);
            sqlParameters[0].Value = Convert.ToString(_username);
            sqlParameters[1] = new SqlParameter("@t01_lastname", SqlDbType.VarChar);
            sqlParameters[1].Value = Convert.ToString(_username);
            return conn.executeSelectQuery(query, sqlParameters);
        }

        /// <method>
        /// Get User Email By Id and return DataTable
        /// </method>
        public DataTable searchById(string _id)
        {
            string query = "select * from [t01_id] where t01_id = @t01_id";
            SqlParameter[] sqlParameters = new SqlParameter[1];
            sqlParameters[0] = new SqlParameter("@t01_id", SqlDbType.VarChar);
            sqlParameters[0].Value = Convert.ToString(_id);
            return conn.executeSelectQuery(query, sqlParameters);
        }
    }
}

Value Object

Value Object is nothing more but a class with the contents GET and SET methods. It’s mainly used to pass Data from one class to another. It’s directly connected with Business Logic Layer and Presentation Layer. As you can see in the diagram object values are being SET in Business Logic Layer and GET from Presentation Layer.

Collapse Copy Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ThreeLayerDemo.Core
{
    public class UserVO
    {
        private int _idUser;
        private string _firstname;
        private string _lastname;
        private string _email;

        /// <constructor>
        /// Constructor UserVO
        /// </constructor>
        public UserVO()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        public int idUser
        {
            get
            {
                return _idUser;
            }

            set
            {
                _idUser = value;
            }
        }

        public string firstname
        {
            get
            {
                return _firstname;
            }

            set
            {
                _firstname = value;
            }
        }

        public string lastname
        {
            get
            {
                return _lastname;
            }
            set
            {
                _lastname = value;
            }
        }

        public string email
        {
            get
            {
                return _email;
            }

            set
            {
                _email = value;
            }
        }
    }
}

Business Logic Layer

Business Logic Layer (BUS) works as a bridge between Presentation Layer and DAO. All the user values received from the presentation layer are being passed to BUS. The results received from the DAO are in row data in Data Table format but in BUS it’s converting into Value Objects (VO). Business Logic Layer (BUS) is the most important class in the whole architecture because it mainly contains all the business logic of the program. Whenever a user wants to update the business logic of the program only need to update this class.

Collapse Copy Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace ThreeLayerDemo.Core
{
    /// <summary>
    /// Summary description for UserBUS
    /// </summary>
    public class UserBUS
    {
        private UserDAO _userDAO;

        /// <constructor>
        /// Constructor UserBUS
        /// </constructor>
        public UserBUS()
        {
            _userDAO  = new UserDAO();
        }

        /// <method>
        /// Get User Email By Firstname or Lastname and return VO
        /// </method>
        public UserVO getUserEmailByName(string name)
        {
            UserVO userVO = new UserVO();
            DataTable dataTable = new DataTable();

            dataTable = _userDAO.searchByName(name);

            foreach (DataRow dr in dataTable.Rows)
            {
                userVO.idUser = Int32.Parse(dr["t01_id"].ToString());
                userVO.firstname = dr["t01_firstname"].ToString();
                userVO.lastname = dr["t01_lastname"].ToString();
                userVO.email = dr["t01_email"].ToString();
            }
            return userVO;
        }

        /// <method>
        /// Get User Email By Id and return DataTable
        /// </method>
        public UserVO getUserById(string _id)
        {
            UserVO userVO = new UserVO();
            DataTable dataTable = new DataTable();
            dataTable = _userDAO.searchById(_id);

            foreach (DataRow dr in dataTable.Rows)
            {
                userVO.idUser = Int32.Parse(dr["t01_id"].ToString());
                userVO.firstname = dr["t01_firstname"].ToString();
                userVO.lastname = dr["t01_lastname"].ToString();
                userVO.email = dr["t01_email"].ToString();
            }
            return userVO;
        }
    }
}

Presentation Layer

Presentation Layer is the only layer which is directly connected with the user. So in this matter, it’s also a really important layer for marketing purposes. Presentation Layer is mainly used for getting user data and then passing it to Business Logic Layer for further procedure, and when data is received in Value Object then it’s responsible to represent value object in the appropriate form which user can understand.

Collapse Copy Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ThreeLayerDemo.Core;

namespace ThreeLayerDemo
{
    public partial class frmLogin : Form
    {
        private UserBUS _userBUS;

        public frmLogin()
        {
            InitializeComponent();
             _userBUS = new UserBUS();
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            UserVO _userVO = new UserVO();
            _userVO = _userBUS.getUserEmailByName(txtUsername.Text);
            if (_userVO.email == null)
                MessageBox.Show("No Match Found!", "Not Found",
			MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            else
                MessageBox.Show(_userVO.email ,"Result",
			MessageBoxButtons.OK,MessageBoxIcon.Information);
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            Close();
        }
    }
}

Summary

Hope this explanation helps the beginner specially looking for a generic approach. There are also some methods which are far better than the architecture described above, mostly with skipping Database Access Layer and Value Object Class, and making it dynamically which is really handy for maintenance in case of frequent database change. I will try to post some in the near future.

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

SQL Server supports a three-part naming convention when you refer to the current server. The ISO standard also supports a three-part naming convention. However, the names used in both naming conventions are different. The information schema views are defined in a special schema named INFORMATION_SCHEMA. This schema is contained in each database. Each information schema view contains metadata for all data objects stored in that particular database. The following table shows the relationships between the SQL Server names and the SQL standard names.

SQL Server name Maps to this equivalent SQL standard name
Database Catalog
Schema Schema
Object Object
user-defined data type Domain

This name-mapping convention applies to the following SQL Server ISO-compatible views.

CHECK_CONSTRAINTS REFERENTIAL_CONSTRAINTS
COLUMN_DOMAIN_USAGE ROUTINES
COLUMN_PRIVILEGES ROUTINE_COLUMNS
COLUMNS SCHEMATA
CONSTRAINT_COLUMN_USAGE TABLE_CONSTRAINTS
CONSTRAINT_TABLE_USAGE TABLE_PRIVILEGES
DOMAIN_CONSTRAINTS TABLES
DOMAINS VIEW_COLUMN_USAGE
KEY_COLUMN_USAGE VIEW_TABLE_USAGE
PARAMETERS VIEWS

Also, some views contain references to different classes of data such as character data or binary data.

When you reference the information schema views, you must use a qualified name that includes the INFORMATION_SCHEMA schema name. For example:

SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLUMN_DEFAULT
FROM AdventureWorks.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N’Product’;

GO

SELECT

OBJECT_NAME(c.OBJECT_ID) TableName

,c.name AS ColumnName

,SCHEMA_NAME(t.schema_id) AS SchemaName

,t.name AS TypeName

,t.is_user_defined

,t.is_assembly_type

,c.max_length

,c.PRECISION

,c.scale

FROM sys.columns AS c

JOIN sys.types AS t

ON c.user_type_id=t.user_type_id

where OBJECT_NAME(c.OBJECT_ID)=’salary_table_detail’

ORDER BY c.OBJECT_ID;

SELECT
OBJECT_NAME(c.OBJECT_ID) TableName
,c.name AS ColumnName
,SCHEMA_NAME(t.schema_id) AS SchemaName
,t.name AS TypeName
,t.is_user_defined
,t.is_assembly_type
,c.max_length
,c.PRECISION
,c.scale
FROM sys.columns AS c
JOIN sys.types AS t
ON c.user_type_id=t.user_type_id
where OBJECT_NAME(c.OBJECT_ID)=’salary_table_detail’
ORDER BY c.OBJECT_ID;

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

 
OverviewIn Microsoft Visual Studio 2008, you can create custom activities that can be consumed in workflows. Creating custom activities lets you encapsulate business logic that applies to different scenarios and that can be used in different workflows. This Microsoft Office Visual How To demonstrates how to create a custom activity to send an e-mail message with an attachment.

Code ItFirst, you must create your custom activity. Then, you can add that to a workflow project and use it to send an e-mail message with an attachment.

Creating a Custom Activity Project

First, create a Visual Studio 2008 Workflow Activity Library project.

To create a Visual Studio 2008 Workflow Activity Library project

  1. Open Visual Studio 2008.
  2. On the File menu, point to New, and then click Project.
  3. Under the Workflow Project Type, select the Workflow Activity Library project template.
  4. In the Name box, type SendMailWithAttachmentActivity, and then click OK.
  5. Rename Activity1 to SendMailWithAttachmentActivity.

Coding Custom Activity

Now that you have a Custom Activity project, you must add code to send an e-mail message with an attachment.

To add code to send an e-mail message with an attachment

  1. The first thing you must do is change your class declaration to inherit directly from Activity instead of SequenceActivity.

    Open your activity in code view, and change SequenceActivity to Activity. Your class definition should look like the following.

    public partial class SendMailWithAttachmentActivity : Activity
    { …

  2. Now you must create some Dependency Properties. Add the following fields inside your class definition.

        public static DependencyProperty ToProperty
          = DependencyProperty.Register(
              "To", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty FromProperty
          = DependencyProperty.Register(
              "From", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty CCProperty
          = DependencyProperty.Register(
              "CC", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty SubjectProperty
          = DependencyProperty.Register(
              "Subject", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty BodyProperty
          = DependencyProperty.Register(
              "Body", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty AttachmentProperty
          = DependencyProperty.Register(
              "Attachment", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty SmtpServerProperty
          = DependencyProperty.Register(
              "SmtpServer", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty InvokeEvent
          = DependencyProperty.Register(
              "Invoke", typeof(EventHandler), typeof(SendMailWithAttachmentsTest));

    Notice that the last field, InvokeEvent, is of type EventHandler. This enables you to add custom code to your activity when it is used in a workflow.

  3. Now, you must add properties for your fields. Add the following code under the fields you just added.

       [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
         [ValidationOption(ValidationOption.Required)]
         [Browsable(true)]
         [Description("Enter any e-mail recipients, separated by semicolons")]
         public string To
         {
            get { return ((string)(base.GetValue(SendMailWithAttachmentsTest.ToProperty))); }
            set { base.SetValue(SendMailWithAttachmentsTest.ToProperty, value); }
         }
    
          [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
         [ValidationOption(ValidationOption.Required)]
         [Browsable(true)]
         [Description("Enter the e-mail sender")]
         public string From
         {
            get { return ((string)(base.GetValue(SendMailWithAttachmentsTest.FromProperty))); }
            set { base.SetValue(SendMailWithAttachmentsTest.FromProperty, value); }
         }
    
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Optional)]
        [Browsable(true)]
        [Description("Enter any carbon copy recipients, separated by semicolons")]
        public string CC
        {
           get { return ((string)(base.GetValue(SendMailWithAttachmentsTest.CCProperty))); }
           set { base.SetValue(SendMailWithAttachmentsTest.CCProperty, value); }
        }
    
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        [Description("Enter the e-mail subject")]
        public string Subject
        {
           get { return ((string)(base.GetValue(SendMailWithAttachmentsTest.SubjectProperty))); }
           set { base.SetValue(SendMailWithAttachmentsTest.SubjectProperty, value); }
        }
    
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
         [ValidationOption(ValidationOption.Optional)]
         [Browsable(true)]
         [Description("Enter the body text of the e-mail")]
         public string Body
         {
            get { return ((string)(base.GetValue(SendMailWithAttachmentsTest.BodyProperty))); }
            set { base.SetValue(SendMailWithAttachmentsTest.BodyProperty, value); }
         }
    
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
         [ValidationOption(ValidationOption.Optional)]
         [Browsable(true)]
         [Description("Enter an attachment file path")]
         public string Attachment
         {
            get { return ((string)(base.GetValue
              (SendMailWithAttachmentsTest.AttachmentProperty))); }
            set { base.SetValue(SendMailWithAttachmentsTest.AttachmentProperty, value); }
         }
    
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
         [ValidationOption(ValidationOption.Required)]
         [Browsable(true)]
         [Description("Enter the Smtp Server for the email")]
         [DisplayName("Smtp Server")]
         public string SmtpServer
         {
            get { return ((string)(base.GetValue
              (SendMailWithAttachmentsTest.SmtpServerProperty))); }
            set { base.SetValue(SendMailWithAttachmentsTest.SmtpServerProperty, value); }
         }

  4. Now, you must add a property for your InvokeEvent field. This EventHandler property lets you add code in a workflow to interact with this activity programmatically. Add this code under the Properties you just added.

       [DescriptionAttribute("Invoke")]
       [CategoryAttribute("Invoke Category")]
       [BrowsableAttribute(true)]
    [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
       public event EventHandler Invoke
       {
          add
          {
             base.AddHandler(SendMailWithAttachmentsTest.InvokeEvent, value);
          }
          remove
          {
             base.RemoveHandler(SendMailWithAttachmentsTest.InvokeEvent, value);
          }
       }

  5. Add a using statement at the top of the class. This enables you to access the ASP.NET 2.0 Mail namespace for sending your e-mail message. Add the following code.

    using System.Net.Mail;

  6. The last thing you must do here is override the Execute method. Add the following method inside your class definition.

        Protected override ActivityExecutionStatus
          Execute(ActivityExecutionContext executionContext)
        {
            // Raise Invoke Event to execute custom code in the workflow.
            this.RaiseEvent(SendMailWithAttachmentsTest.InvokeEvent,
              this, EventArgs.Empty);
    
            // Set reference to Smtp Server.
            SmtpClient smtp = new SmtpClient(SmtpServer);
    
            // Create mail message.
            MailMessage msg = new MailMessage();
            msg.To.Add(To);
            msg.From = new MailAddress(From);
            if (!String.IsNullOrEmpty(CC))
            {
                msg.CC.Add(CC);
            }
            if (!String.IsNullOrEmpty(Subject))
            {
                msg.Subject = Subject;
            }
            if (!String.IsNullOrEmpty(Body))
            {
                msg.Body = Body;
            }
            if (!String.IsNullOrEmpty(Attachment))
            {
                msg.Attachments.Add(new Attachment(Attachment));
            }
    
            // Send the e-mail.
            smtp.Send(msg);
    
            // Indicate that the activity has completed.
            return ActivityExecutionStatus.Closed;
    }

Installing a Custom Activity

Before you can use your custom activity, you must install it in the global assembly cache (GAC). For an assembly to be installed in the GAC, you must give it a strong name.

To install the custom activity to the GAC

  1. First, give your assembly a strong name. In Solution Explorer, right-click the project, and then select Properties.
  2. Select the Signing tab.
  3. Select the Sign the assembly check box.
  4. In the Choose a strong name key file list, select New.
  5. In the Key file name text box, type Key.
  6. In this demonstration, we are not concerned with security, so clear the Protect my key file with a password check box. Click OK.

    Now your assembly is strong named, and all you have to do is install it to the global assembly cache.

  7. Save and build the project.
  8. Open a Visual Studio 2008 command prompt.
  9. Navigate to the Activity solution directory, and run the following command:

    gacutil /if SendMailWithAttachmentActivity.dll

Now, that you have successfully installed your activity, you can use it from a workflow project.

Creating a Workflow Project

Next, you create a Sequential Workflow project to use your custom activity.

To create a Visual Studio 2008 Sequential Workflow project

  1. Start Visual Studio 2008.
  2. On the File menu, point to New, and then click Project.
  3. Under the Office Project Type, select the SharePoint 2007 Sequential Workflow project template.
  4. In the Name box, type SendEmailWithAttachmentWF. Click OK.
  5. Type a valid SharePoint Web URL. The example uses http://moss.litware.com. Click Next.
  6. Select a library or list to associate with your workflow, and click Next.
  7. Leave the default options for how a workflow can be started, Manually by users and When an Item is created. Click Finish.

Adding a Custom Activity to the Toolbox

Now that you have created your Sequential Workflow project, you must add your custom activity to your Toolbox before you can use it.

To add the custom activity to the Visual Studio 2008 Toolbox

  1. On the Tools menu, select Toolbox items.
  2. Select the Activities tab.
  3. Click Browse, and browse to the SendMailWithAttachmentActivity.dll in your Activity solution directory. Click Open.
  4. Click OK.
  5. Your activity is now available in the Toolbox.

    Figure 1. Toolbox with new activity available

    Toolbox with activity available

    Note Note:

    If you have a toolbox category selected, the activity is added to that category by default. You can drag the activity to another category if you want.

Adding a Custom Activity to the Workflow

Now, you must add your custom activity to your simple workflow.

To add the custom activity to the workflow

  1. From the Toolbox, drag the SendMailWithAttachmentActivity to be under the onWorkflowActivated1 activity.
  2. Open the Properties window, and rename it to sendMailWithAttachmentActivity.
  3. You can set the activity properties from within the Properties window. Instead, you will do that in code. Select the Event view in the Properties window.
  4. You should see a single event, Invoke. Double-click this property.

    Figure 2. Properties window

    Properties window 

    This takes you to the code-behind class, and you will see that a method stub has been auto-generated for you.

  5. Add the following code inside this method.

        SendMailWithAttachmentActivity.To = "nicolec@litwareinc.com";
        SendMailWithAttachmentActivity.From = "willisj@litwareinc.com";
        SendMailWithAttachmentActivity.CC = "willisj@litwareinc.com";
        SendMailWithAttachmentActivity.Subject = "Email with Attachment Testing.";
        SendMailWithAttachmentActivity.Body = "This email should have an attachment.";
        SendMailWithAttachmentActivity.Attachment
          = @"C:\Documents and Settings\Administrator\Desktop\code snippets.txt"; 
    
        SendMailWithAttachmentActivity.SmtpServer =
          workflowProperties.Site.WebApplication.OutboundMailServiceInstance.Server.Address;

  6.  
Note Note:

The purpose of this demonstration is to show you how to create and consume a custom activity. In a real-world scenario, you would never hard-code these values. You would retrieve them programmatically, or possibly through an Initiation form or a Task form.

Running the Workflow Project from Visual Studio 2008

Press F5 to run your workflow. When you activate this workflow on a document in a document library, an e-mail message is generated and sent with the attachment you specified.

Figure 3. E-mail message with attachment

E-mail with attachment

http://glorix.blogspot.com/2007/08/custom-action-locations-and-groupid.html

I’ve been wandering around the internet to find all the locations that you can define to add your custom action at. You see, I want to add a link near the ‘Welcom <User>, My Site, My Links’ section (aka the global links section). What I found was the following :

Using CustomAction to modify system pages by Chris O’ Brien

  • Microsoft.SharePoint.ContentTypeTemplateSettings
  • Microsoft.SharePoint.ContentTypeSettings
  • Microsoft.SharePoint.Administration.ApplicationCreated
  • Office.Server.ServiceProvider.Administration (Shared Services/SSP links)
  • Microsoft.SharePoint.ListEdit.DocumentLibrary
  • Microsoft.SharePoint.Workflows
  • NewFormToolbar
  • DisplayFormToolbar
  • EditFormToolbar
  • Microsoft.SharePoint.StandardMenu (SiteActions menu)
  • Mcrosoft.SharePoint.Create (_layouts/create.aspx – the screen used to specify what you want to create on your site)
  • Microsoft.SharePoint.ListEdit (the screen used to edit the properties of a list item)
  • EditControlBlock (image below)

That’s more than Microsoft specified on their page How to: Add Actions to the User Interface. But still I didn’t found my answer on how to add a link to the global links section. Then I went looking in the 12/Templates/Controltemplates folder for the usercontrol that renders the ‘Welcome <User>’ section, named “Welcome.ascx”. There I found the following bit :

     <SharePoint:FeatureMenuTemplate runat="server"
         FeatureScope="Site"
         Location="Microsoft.SharePoint.StandardMenu"
         GroupId="PersonalActions"
         id="ID_PersonalActionMenu"
         UseShortId="true"
         >

Now it’s the GroupId that interested me.. So I created a feature that looks this (first part being the feature.xml and the second being the elements.xml) :

<Feature
  Id="AA929AFF-4602-4d7f-A501-B80AC9A4BB52"
  Title="Add Links to user section"
  Description="Feature that adds a link to Welcome User section"
  Scope="WebApplication"
  xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="Elements.xml" />
  </ElementManifests>
</Feature>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <CustomAction
        Id="0acdbd94-eba8-11db-8314-0800200c9a66"
        GroupId="PersonalActions"
        Location="Microsoft.SharePoint.StandardMenu"
        Sequence="1000"
        Title="View Terms of Use"
        Description="Open the Terms of Use document"
        ImageUrl="_layouts/1033/images/KpiListView.png">
        <UrlAction Url="_layouts/termsofuse.aspx"/>
    </CustomAction>
</Elements>

So how does that look in real life I hear you wonder… well like this :

http://www.tonstegeman.com/Blog/Lists/Posts/Post.aspx?List=70640fe5%2D28d9%2D464f%2Db1c9%2D91e07c8f7e47&ID=60

In the new version of the Content By Type webpart, I added the option to rollup items into a calendar. In a later post I will describe how you can do that using the webpart. In this post I will show you how I did it in the code. When you start it all seems very easy, but there were a few things that caused me some headaches. I hope you don’t run into them as well after reading this item.

Step 1 – Setting up the controls

I implemented all the calendar specific code in a special control:

public class SharePointCalendar : Control

In the CreateChildControls of my webpart, I just add this control to the collection:

protected override void CreateChildControls()
{
    base.CreateChildControls();
    SharePointCalendar calendar = new SharePointCalendar();
    Controls.Add(calendar);
}

In the CreateChildControls of my SharePointCalendar class, I setup the SPCalendarView and add it to the controls collection:

private SPCalendarView _view;

/// <summary>
/// Create the SharePoint calendar. Uses the SharePoint SPCalendarView object.
/// </summary>
protected override void CreateChildControls()
{
    base.CreateChildControls();
    _view = new SPCalendarView();
    _view.EnableViewState = true;
    _view.Width = Unit.Percentage(100);
    _view.DataSource = GetCalendarItems();
    DataBind();
    Controls.Add(_view);
}

You can find SPCalendarView in the Microsoft.SharePoint.WebControls namespace.

Step 2 – Adding data and testing

The data that will be displayed in the calendar is loaded in GetCalendarItems. In this case it is dummy data, but you will get the idea:

private SPCalendarItemCollection GetCalendarItems()
{
    // Create a new collection for the calendar items
    // This is an item with a start and end date.
    SPCalendarItemCollection items = new SPCalendarItemCollection();

    // Add the first dummy item
    SPCalendarItem item = new SPCalendarItem();
    item.StartDate = DateTime.Now;
    item.EndDate = DateTime.Now.AddHours(1);
    item.hasEndDate = true;
    item.Title = "First calendar item";
    item.DisplayFormUrl = "/News";
    item.Location = "Utrecht";
    item.Description = "This is the first test item in the calendar rollup";
    item.IsAllDayEvent = false;
    item.IsRecurrence = false;
    item.CalendarType = Convert.ToInt32(SPCalendarType.Gregorian);
    items.Add(item);

    // Add the second item. This is an all day event.
    SPCalendarItem item2 = new SPCalendarItem();
    item2.StartDate = DateTime.Now.AddDays(-1);
    item.hasEndDate = true;
    item2.Title = "Second calendar item";
    item2.DisplayFormUrl = "/News";
    item2.Location = "Utrecht";
    item2.Description = "This is the second test item in the calendar rollup";
    item2.IsAllDayEvent = true;
    item2.IsRecurrence = false;
    item2.CalendarType = Convert.ToInt32(SPCalendarType.Gregorian);
    items.Add(item2);

    // return the collection
    return items;
}

If you now build your webpart and add it to a page, it should look like this:

calendar01

Step 3 – The ViewType

Looks nice and it indeed it very simple to do. But now you click one of the links “Week” or “Day” to switch to the daily or weekly view. That doesn’t work. The webpart simply does what it does and it shows you the monthly view. If you look at the url however, you will see that the calendar view added a querystring parameter called “CalendarPeriod“.

Add the following snippet to the CreateChildControls of the SharePointCalendar to make it work:

if (Page.Request.QueryString["CalendarPeriod"] != null)
{
    switch (Page.Request.QueryString["CalendarPeriod"].ToString().ToLower())
    {
        case "day":
            _view.ViewType = "day";
            break;
        case "week":
            _view.ViewType = "week";
            break;
        case "timeline":
            _view.ViewType = "timeline";
            break;
        default:
            _view.ViewType = "month";
            break;
    }
}

The documentation for the ViewType property shows you the possible values, but please notice that you need to set them in lower case!. Not sure what the option “timeline” does. It looks like a normal monthly view if you use it.

Step 4 – The DisplayFormUrl problem

The property DisplayFormUrl expects are relative url to the item that you added to the calendar. In the sample above, I added a url to the News site. If you look at the properties of the hyperlink, you will see this link:

http://cbt/News?ID=

The calendar view automatically adds a querystring parameter ID to your urls. In this case this is not a problem. In the Content By Type webpart however, I add the same links that are generated by the out of the box ContentQuery webpart. These urls look like this:

http://cbt/_layouts/CopyUtil.aspx?Use=id&Action=dispform&ItemId=1&ListId={70fbb8db-c7b8-4b32-bf77-f61a13b3e0fc}&WebId={087c3dd8-b0a9-4960-9509-da8887d979b6}&SiteId={9fb94730-cc85-4924-957f-7504f415fe0f}

When you add “?ID=” to that url (that is what the calendar view does), your link will not work and the page will display an “Unknown error“:

calendar02

In the first approach I tried to fix the urls in javascript, but that didn’t work. I was able to trim the “?ID=” bit, but something else kept on adding it back in. I ended up creating a page like the CopyUtil page. When I set the DisplayFormUrl property, I encode the Url that I want to redirect to and add that as a querystring parameter to my redirect page called “tstredirect.aspx”:

string link = /_layouts/CopyUtil.aspx?Use=id&Action=dispform&ItemId=1&ListId={70fbb8db-c7b8-4b32-bf77-f61a13b3e0fc}&WebId={087c3dd8-b0a9-4960-9509-da8887d979b6}&SiteId={9fb94730-cc85-4924-957f-7504f415fe0f}
string urlStart = SPContext.Current.Site.ServerRelativeUrl;
if (urlStart == "/")
    urlStart = string.Empty;
link = string.Format("{0}/_layouts/tst/tstredirect.aspx?GoTo={1}", urlStart, System.Web.HttpUtility.UrlEncode(link));

item.DisplayFormUrl = link;

In that tstredirect page, I decode the querystring GoTo parameter and redirect to that url.

I am not very happy with that last approach, there should be a better way. If you have a suggestion, please let me know. So after all, it still is pretty easy to use the SPCalendarView in your webparts, if you are aware of these things. In the next post I will show you how I exactly implemented it in the Content By Type webpart.

http://www.sharepointboost.com/passwordchange.html

SharePoint Password Change contains two Web Parts: SharePoint Password Change Web Part and SharePoint Password Expire Warning Web Part.

You can change your own password on Password Change page or Password Change Web Part. To enter Password Change page, you can click the “Change password” link on SharePoint Welcome menu.

 SharePoint Password Change allows users change their passwords from the welcome page without help from administrators

You can also change password by adding SharePoint change password Web Part on a page. When you enter this page, Password Change Web Part will automatically detect your domain and name. After you have set your password, Password Change Web Part will verify the new password and save the change. If current password is incorrect or does not meet password policy, you will receive a piece of error message.

Users can reset SharePoint passwords directly without administrator intervention

Password Expire Warning Web Part can notify users to change password and provide users a URL to go to the password change page. You can configure the URL and decide how many days before expiration date should it notify users. When you have access to the page on which Password Expire Warning Web Part is configured, the Web Part will automatically identify your domain, user name and user account expiration date. If your password expires, the notification and URL will display.

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

To define a custom action for a particular menu, you must identify the menu by setting the location to the appropriate Windows SharePoint Services namespace, and by using the ID that Windows SharePoint Services uses to identify the specific location.

For example, to add a custom action to the Site Settings page, set the Location attribute of the CustomAction element toMicrosoft.SharePoint.SiteSettings.and specify a particular area within the page through the GroupId attribute.

Different actions may require using different CustomAction attributes to identify the menu in which to place a custom menu item. But you may also need to specify other parameters for the action, for example, to specify a version, user permissions required to perform the action, or placement in relation to existing actions in the menu. The custom actions of the following example show a variety of attributes.

See Default Custom Action Locations and IDs for a list of the default custom action IDs and locations that are used in an installation of Windows SharePoint Services.