sharepoint custom workflow activity is doing nothing, not even log messages - sharepoint

I am trying to create a custom workflow activity which gives me the list of recipients that I am storing in list. But once I deploy and start the workflow nothing is happening, not even log messages are coming. So i tried to debug the code but breakpoints are not set and I am getting the error "The Breakpoint will not currently be hit. No symbols have been loaded for this document." Can anyone please help me to deal with this issue.
Below are the steps I have followed in creating this activity.
1. created a workflow activity library.
(please find my code file attached)
added .dll to GAC
updated web.config and WSS.actions files.
Now I see the action in designer, so i have created a workflow using designer.
strted the workflow manually on an item.
Here nothing is happening, not even an error. Please let me know if you need any further information.
Please find the code below.
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using Microsoft.SharePoint;
using System.Diagnostics;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;
namespace CustomWorkflowActivityLibrary
{
public partial class CustomWorkflowActivity: SequenceActivity
{
SPList _list;
private EventLog _log;
SPFieldUserValueCollection objUserFieldValueCol;
string semailsettingKeyword1;
string semailsettingKeyword2;
public CustomWorkflowActivity()
{
InitializeComponent();
}
public static DependencyProperty __ContextProperty = DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof(CustomWorkflowActivity));
[DescriptionAttribute("__Context")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
public WorkflowContext __Context
{
get { return ((WorkflowContext)(base.GetValue(CustomWorkflowActivity.__ContextProperty))); }
set { base.SetValue(CustomWorkflowActivity.__ContextProperty, value); }
}
public static DependencyProperty ListIdProperty = DependencyProperty.Register("ListId", typeof(string), typeof(CustomWorkflowActivity));
[DescriptionAttribute("ListId")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
public string ListId
{
get { return ((string)(base.GetValue(CustomWorkflowActivity.ListIdProperty))); }
set { base.SetValue(CustomWorkflowActivity.ListIdProperty, value); }
}
public static DependencyProperty ListItemProperty = DependencyProperty.Register("ListItem", typeof(int), typeof(CustomWorkflowActivity));
[DescriptionAttribute("ListItem")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
public int ListItem
{
get { return ((int)(base.GetValue(CustomWorkflowActivity.ListItemProperty))); }
set { base.SetValue(CustomWorkflowActivity.ListItemProperty, value); }
}
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
_log = new EventLog("Add Description");
_log.Source = "Share Point Workflows";
try
{
//Execute method as a elevated method
SPSecurity.CodeToRunElevated elevatedExecuteMethod = new SPSecurity.CodeToRunElevated(ExecuteMethod);
SPSecurity.RunWithElevatedPrivileges(elevatedExecuteMethod);
}
catch (Exception ex)
{
_log.WriteEntry("Error" + ex.Message.ToString(), EventLogEntryType.Error);
}
return ActivityExecutionStatus.Closed;
}
private void ExecuteMethod()
{
try
{
//retrieveing the Site object
SPSite _site = new SPSite(__Context.Site.Url);
//retrieveing the Web object
SPWeb _web = (SPWeb)(__Context.Web);
//retrieveing the list object
_list = _web.Lists[new Guid(this.ListId)];
//retrieveing the list item object
SPListItem _listItem = _list.GetItemById(this.ListItem);
_site.AllowUnsafeUpdates = true;
_web.AllowUnsafeUpdates = true;
string semailsubject = _listItem["E-Mail Subject"].ToString();
string semailfrom = _listItem["emailfrom"].ToString();
_log = new EventLog("get vendor info");
_log.WriteEntry("semailsubject");
_log.WriteEntry("semailfrom");
/* _listItem.Update();
_list.Update();
_site.AllowUnsafeUpdates = false;
_web.AllowUnsafeUpdates = false;*/
using (SPSite mysite = new SPSite("http://dlglobaltest.dl.com/Admin/IT/Application%20Development%20Group/LibraryEmailDistribution"))
{
using (SPWeb myweb = mysite.OpenWeb())
{
SPList settingsList = myweb.Lists["EmailDistributionSettings"];
SPQuery oQuery = new SPQuery();
oQuery.Query = "<Where><Eq><FieldRef Name='Sender' /><Value Type='Text'>" + semailfrom + "</Value></Eq></Where>";
SPListItemCollection ColListItems = settingsList.GetItems(oQuery);
foreach (SPListItem oListItem in ColListItems)
{
semailsettingKeyword1 = oListItem["Keyword1"].ToString();
semailsettingKeyword2 = oListItem["Keyword2"].ToString();
//SPFieldUserValue objUserFieldValue = new SPFieldUserValue(myweb, oListItem["Recipients"].ToString());
if ((semailsubject.Contains(semailsettingKeyword1)) || (semailsubject.Contains(semailsettingKeyword2)))
{
objUserFieldValueCol = new SPFieldUserValueCollection(myweb, oListItem["Recipients"].ToString());
_log = new EventLog(objUserFieldValueCol.ToString());
}
}
}
}
}
catch (Exception ex)
{ }
}
}
}
Web.Config:
<authorizedType Assembly="CustomWorkflowActivityLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a95e146fc1062337" Namespace="CustomWorkflowActivityLibrary" TypeName="*" Authorized="True" />
WSS.Actions:
<Action Name="Get Recipients"
ClassName="CustomWorkflowActivityLibrary.CustomWorkflowActivity"
Assembly="CustomWorkflowActivityLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a95e146fc1062337"
AppliesTo="all" Category="Custom">
<RuleDesigner Sentence="Get Recipients for %1 ">
<FieldBind Field="ListId,ListItem" Text="this list" Id="1" DesignerType="ChooseListItem" />
</RuleDesigner>
<Parameters>
<Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext" Direction="In" />
<Parameter Name="ListId" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="ListItem" Type="System.Int32, mscorlib" Direction="In" />
</Parameters>
</Action>
Thanks,

I am not sure if this will help but you could try changing the following line in your code from this:
SPSecurity.RunWithElevatedPrivileges(elevatedExecuteMethod);
To this:
SPSecurity.RunWithElevatedPrivileges(delegate(){
ExecuteMethod();
});

Another shot-in-the-dark reply:
Try changing the class you're inheriting ( http://msdn.microsoft.com/en-us/library/ms173149(v=VS.80).aspx ) from SequenceActivity to Activity (SequenceActivity inherits from CompositeActivity, which itself inherits from Activity. See: http://msdn.microsoft.com/en-us/library/system.workflow.activities.sequenceactivity(v=VS.90).aspx )
If that doesn't work, try removing your constructor entirely. You should be able to use the base (Sequence)Activity constructor (since you're inheriting the class, not implementing it)
Hope that helps...

Related

Sharepoint 2013 GetListItems web service returning a list of folders in library, instead of list of files within a folder

I'm having a problem being able to get the list of items within a folder, it keeps giving me the list of folders in the library, and not the list of files within the specified folder.
I'm using a C# program, using the following method to call the web service GetListItems, and it all seems to work up to a point:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/sharepoint/soap/GetListItems", RequestNamespace="http://schemas.microsoft.com/sharepoint/soap/", ResponseNamespace="http://schemas.microsoft.com/sharepoint/soap/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public System.Xml.XmlNode GetListItems(string listName, string viewName, System.Xml.XmlNode query, System.Xml.XmlNode viewFields, string rowLimit, System.Xml.XmlNode queryOptions, string webID) {
object[] results = this.Invoke("GetListItems", new object[] {
listName,
viewName,
query,
viewFields,
rowLimit,
queryOptions,
webID});
return ((System.Xml.XmlNode)(results[0]));
}
The values of the parameters are as follows:
listName = "Letters"
viewName = null
query = null
viewFields.OuterXml = "<ViewFields>
<FieldRef Name=\"ID\" />
<FieldRef Name=\"Title\" />
<FieldRef Name=\"Modified\" />
<FieldRef Name=\"Status\" />
<FieldRef Name=\"_UIVersion\" />
<FieldRef Name=\"_UIVersionString\" />
<FieldRef Name=\"EpisodeId\" />
</ViewFields>"
rowLimit = null
queryOptions.OuterXml = "<QueryOptions>
<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>
<Folder>http://D3TVCAPP-APP02.test.local/Letters/ABBOTT, Nash _489611</Folder>
<DateInUtc>TRUE</DateInUtc>
</QueryOptions>"
webID = null
And it actually returns a result, it is hitting the service ok, the result looks like this:
results.OuterXml =
"<listitems xmlns:s=\"uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882\" xmlns:dt=\"uuid:C2F41010-65B3-11d1-A29F-00AA00C14882\" xmlns:rs=\"urn:schemas-microsoft-com:rowset\" xmlns:z=\"#RowsetSchema\" xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\">
<rs:data ItemCount=\"2\">
<z:row
ows_ID=\"84\"
ows_Modified=\"2021-06-09T09:50:11Z\"
ows__UIVersion=\"1\"
ows__UIVersionString=\"0.1\"
ows__ModerationStatus=\"2\"
ows__Level=\"2\"
ows_UniqueId=\"84;#{C8E8EC38-6DD5-4275-873A-B829BA850A54}\"
ows_owshiddenversion=\"1\"
ows_FSObjType=\"84;#1\"
ows_Created_x0020_Date=\"84;#2021-06-09T09:50:11Z\"
ows_ProgId=\"84;#\"
ows_FileLeafRef=\"84;#ABBOTT, Nash _489611\"
ows_PermMask=\"0x7fffffffffffffff\"
ows_FileRef=\"84;#Letters/ABBOTT, Nash _489611\"
ows_Editor=\"1;#John Smith\"
ows_MetaInfo=\"84;#\"
ows_Last_x0020_Modified=\"84;#2021-06-09T09:50:14Z\"
/>
<z:row
ows_ID=\"3\"
ows_Modified=\"2020-11-04T13:02:42Z\"
ows__UIVersion=\"1\"
ows__UIVersionString=\"0.1\"
ows__ModerationStatus=\"2\"
ows__Level=\"2\"
ows_UniqueId=\"3;#{1CA7B690-BF90-41EC-A5EA-E910C8D72376}\"
ows_owshiddenversion=\"1\"
ows_FSObjType=\"3;#1\"
ows_Created_x0020_Date=\"3;#2020-11-04T13:02:42Z\"
ows_ProgId=\"3;#\"
ows_FileLeafRef=\"3;#SMITH, JOHN _483835\"
ows_PermMask=\"0x7fffffffffffffff\"
ows_FileRef=\"3;#Letters/SMITH, JOHN _483835\"
ows_Editor=\"1;#John Smith\"
ows_MetaInfo=\"3;#\"
ows_Last_x0020_Modified=\"3;#2020-11-06T16:59:03Z\"
/>
</rs:data>
</listitems>"
Apologies for the wall of code, I just hope that someone can help me and want to provide as much info as possible. I can't figure this one out, I feel like I'm doing everything right. Anyone got any idea what I 'm doing wrong?
C# Programming give for developers two options to consumes SharePoint data; seeing your code, I think you try to consume SharePoint data using REST API approach. The REST API approach is commonly used to make interfaces with SharePoint and external Systems written by other programming languages (different of C#) and not used a lot by C# developer community in frequency; but, it's need to be clear: it's not a rule and it's not impossible to consumes SharePoint data using REST API from C#, but this is more "difficultly" comparing with CSOM approach.
Now, I will show you an example using CSOM approach to get files from specific folder, and you get your conclusions:
First of all, download and install SharePoint 2013 Client SDK;
After installed SDK, create some standalone app, like a Console App using .NET Framework 4.5 or later;
Add in References (search in Framework) two DLLs: Microsoft.SharePoint.Client.dll and Microsoft.SharePoint.Client.Runtime.dll;
Add this code-file bellow in your Console App Project:
using System;
using System.Net;
using System.Security;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;
namespace SharePoint.Csom.Approach
{
public class SharePointDocumentModel
{
public string FileName { get; set; }
public string Url { get; set; }
public string Version { get; set; }
}
public class SharePointDocuments : IDisposable
{
private bool _disposed = false;
protected readonly ClientContext _clientContext;
public SharePointDocuments(string sharepointSiteUrl, string user, SecureString password)
{
if (string.IsNullOrWhiteSpace(sharepointSiteUrl) || !sharepointSiteUrl.StartsWith("http"))
{
throw new InvalidOperationException("Impossible to connect with invalid URL.");
}
this._clientContext = new ClientContext(sharepointSiteUrl);
this._clientContext.AuthenticationMode = ClientAuthenticationMode.Default;
this._clientContext.Credentials = new NetworkCredential(user, password);
}
public IEnumerable<SharePointDocumentModel> GetFiles(string folderRelativeURL)
{
Web web = this._clientContext.Web;
this._clientContext.Load(web);
this._clientContext.ExecuteQuery();
Folder folder = web.GetFolderByServerRelativeUrl(web.ServerRelativeUrl + folderRelativeURL);
this._clientContext.Load(folder);
this._clientContext.ExecuteQuery();
FileCollection fileCol = folder.Files;
this._clientContext.Load(fileCol);
this._clientContext.ExecuteQuery();
foreach (File file in fileCol)
{
string fileVersion = null;
FileVersionCollection oFileVersionCollection = file.Versions;
this._clientContext.Load(oFileVersionCollection);
this._clientContext.ExecuteQuery();
foreach (FileVersion oFileVersion in oFileVersionCollection)
{
fileVersion = oFileVersion.VersionLabel;
}
yield return new SharePointDocumentModel()
{
FileName = file.Name,
Url = file.ServerRelativeUrl,
Version = fileVersion
};
}
}
public void Dispose()
{
this.Dispose(true);
}
private void Dispose(bool disposing)
{
if (this._disposed)
{
return;
}
if (disposing)
{
if (null != this._clientContext)
{
this._clientContext.Dispose();
}
}
this._disposed = true;
}
~SharePointDocuments()
{
this.Dispose(false);
}
}
}
At Program class and in Main method, add this code:
List<SharePoint.Csom.Approach.SharePointDocumentModel> files = new List<SharePoint.Csom.Approach.SharePointDocumentModel();
using (SharePoint.Csom.Approach.SharePointDocuments sharepoint = new SharePoint.Csom.Approach.SharePointDocuments("http://D3TVCAPP-APP02.test.local", "user", "password"))
{
files = sharepoint.GetFiles("/Letters/ABBOTT, Nash _489611").ToList();
}
Voilá!
After made your tests, give us the feedback.
Thanks.

EventReceiver to Create folder sharepoint 2010

I have this event receiver c# class that I am trying to implement on a Sharepoint site. It did not work. I have deployed it from visual studio 2010 after it was build ok. Does anyone see what is the problem? Is the code ok? or is the problem on the SP? Thank you.
- here is the new code
using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
namespace EventReceiverCFolder.EventReceiver1
{
/// <summary>
/// List Item Events
/// </summary>
public class EventReceiver1 : SPItemEventReceiver
{
/// <summary>
/// An item is being added.
/// </summary>
public override void ItemAdded(SPItemEventProperties properties)
{
try
{
if (properties.ListTitle == "CF") // list where the item was added
{ // if item was added to this list then create a folder on - Dlib - list
UpdateFolder(properties);
}
}
catch (Exception ex)
{
properties.Status = SPEventReceiverStatus.CancelWithError;
properties.ErrorMessage = ex.Message;
properties.Cancel = true;
}
}
private void UpdateFolder(SPItemEventProperties properties)
{
string foldername = properties.ListItem["Title"].ToString();
try
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//inside RunWithElevatedPriviliges I need to open a new site (an elevated site)
using (SPSite site = new SPSite(properties.Web.Site.ID))
{
using (SPWeb web = site.OpenWeb())
{
web.AllowUnsafeUpdates = true;
SPList list = web.Lists.TryGetList("DLib"); // this is doc Library where the new folder will be created
//note that we are creating a list item, not a folder - a folder IS a list item
SPListItem createdFolder = list.Items.Add(list.RootFolder.ServerRelativeUrl, SPFileSystemObjectType.Folder, null);
if (createdFolder != null)
{
createdFolder["Name"] = foldername;
createdFolder.Update();
}
list.Update();
}
}
});
}
finally { }
}
}
}
Don't do this: SPUser privilegedAccount = properties.Web.AllUsers[#"SHAREPOINT\SYSTEM"];
Read up on using SPSecurity.RunWithElevatedPrivileges. See the MSDN documentation here.
Also don't do a using (SPSite... and inside the using block you try to get the web via SPContext.Current - that web won't be elevated anymore.
The correct way is something along these lines (I didn't try this, so it' just to give you an idea where you are headed):
private void UpdateFolder(SPItemEventProperties properties)
{
string foldername = properties.ListItem["Title"].ToString();
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//inside RunWithElevatedPriviliges I need to open a new site (an elevated site)
using (SPSite site = new SPSite(properties.Web.Site.ID))
{
using (SPWeb web = site.OpenWeb())
{
web.AllowUnsafeUpdates = true;
SPList list = web.Lists.TryGetList("ListTitle"); //is that really the list title?
//note that we are creating a list item, not a folder - a folder IS a list item
SSPListItem createdFolder = list.Items.Add(list.RootFolder.ServerRelativeUrl, SPFileSystemObjectType.Folder, null);
if (newFolder != null)
{
createdFolder["Name"] = foldername;
createdFolder.Update();
}
list.Update();
}
}
});
}
Also try to debug your code, set breakpoints etc.
I had to get folder name like this:
string foldername = Convert.ToString(properties.AfterProperties["Title"]);
Did you try to debug it? try to debug and tell us what error you are getting.
BUT before you debug first use sharepoint manager to see if your event receiver is attached properly.
If you dont know how to debug sharepoint event receiver then please see this

Sharepoint - Item added eventhandler properties do not work

I've started programming event handlers.
At first I added some items to lists with hard coded values.
Everything worked fine, but then I switched to using properties.OpenWeb() and tried to get the URL with web.Url.ToString() - doing this the handlers won't work and do not emit any error.
Do I have to change any configuration?
Have you got a way to solve my problem?
By the way if I try to get values, they are all null.
I am using WSS 3.0 and VS 2008, please see my code below, and thanks!
public override void ItemAdded(SPItemEventProperties properties)
{
SPSite site = new SPSite("http://air_sim:1431/");
SPWeb web = site.RootWeb;
SPList List = web.Lists["Announcements"];
base.ItemAdded(properties);
SPWeb web1 = properties.OpenWeb();
SPListItem newitem = List.Items.Add();
newitem["Title"] = "test";
newitem["Body"] = web1.Url.ToString();
newitem.Update();
}
By the way i found this code on msdn.
It doesn't work. No error..nothing, and of couse the condition is true.
public override void ItemAdding(SPItemEventProperties properties)
{
using(SPWeb oWebsite = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl))
{
SPListItemCollection collItems = oWebsite.Lists[properties.ListTitle].Items;
if (collItems.Count >1)
{
properties.Cancel = true;
properties.ErrorMessage = "Adding items to this list is not supported because it already contains " +
collItems.Count.ToString() + " items.";
}
}
}
please be sure of that the "Type" in "receiver" in the Elements.xml as following :
<Type>ItemAdded</Type>
your "receiver" node should be something like :
<Receiver>
<Name>ERItemAdded</Name>
<Type>ItemAdded</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>NameSpace.ClassName</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>

Customizing default.master in WSS 3.0

Does anyone know how to customize the master page (i.e. default.master) for a WSS 3.0 site? Actually, I already know how to customize the master page (i.e. via SharePoint Designer, or a text editor), I'm more interested in learning how to tell WSS 3.0 to use my customized master page.
I've renamed the default.master with my customized version and that works, but that sets it for all WSS sites. I want to be able to use version A of a master page for site collection A, and a separate master page for other site collections.
Note, I'm NOT referring to MOSS 2007. I already know how to set the master page for MOSS 2007. I can't seem to figure out how to do it for WSS 3.0 though.
Thanks.
WSS pages use Master Pages just like regular web apps. However, the value if the MasterPageFile attribute is a token, and is set to "~default.master". This token gets replaced with the actual reference to the master page in the page's PreInit method.
You can change the value of ~default.master to anything you like. But a better solution is to do the same type of thing that SharePoint does.
I added an HttpHandler to my SharePoint site. The handler attaches to the PreRequestHandlerExecute method, and changes the value of the master page file attribute before SharePoint starts rendering the page.
Add a line to the httpModules section of the web.config that looks like this:
Then create a class like this:
namespace MyClassLibrary.Utility
{
public class MasterPageHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
}
void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
bool useCustomMasterPages = Convert.ToBoolean(ConfigurationManager.AppSettings["ShowCustomMasterPages"].ToString());
if (useCustomMasterPages)
{
Page page = HttpContext.Current.CurrentHandler as Page;
if (page != null)
{
page.PreInit += new EventHandler(page_PreInit);
}
}
}
void page_PreInit(object sender, EventArgs e)
{
bool useThreeColumnMaster = Convert.ToBoolean(ConfigurationManager.AppSettings["UseThreeColumnMasterOnDefaultPage"].ToString());
try
{
Page page = sender as Page;
if (page != null && SPContext.Current != null)
{
string url = page.Request.Url.AbsolutePath.ToLower();
if (url.IndexOf("/public/") > -1)
{
if (url.IndexOf("sitemap.aspx") == -1)
{
page.MasterPageFile = "~/_catalogs/masterpage/edge_con.master";
}
else
{
page.MasterPageFile = "";
}
}
else if (url.IndexOf("default.aspx") > -1)
{
if (useThreeColumnMaster)
{
page.MasterPageFile = "~/_catalogs/masterpage/edge_con.master";
}
else
{
page.MasterPageFile = "~/_catalogs/masterpage/edge.master";
}
}
else if (url.IndexOf("sitemap.aspx") > -1)
{
//
// Sitemap pages should not have a master page
//
page.MasterPageFile = "";
page.Controls.Clear();
}
else if (url.IndexOf("/admin/") > -1)
{
page.MasterPageFile = "~/_catalogs/masterpage/edge.master";
}
else if (url.IndexOf("/member/") > -1)
{
page.MasterPageFile = "~/_catalogs/masterpage/edge.master";
}
else if (url.IndexOf("/supplier/") > -1)
{
page.MasterPageFile = "~/_catalogs/masterpage/edge.master";
}
else if (page.MasterPageFile == "~masterurl/default.master")
{
page.MasterPageFile = "~/_catalogs/masterpage/edge.master";
}
}
}
catch (Exception exception)
{
LogWriter logWriter = new LogWriter();
logWriter.WriteToLog("Could not set master page: " + exception.Message, LogType.MasterPage, DateTime.Now);
}
}
public void Dispose()
{
}
}
}
Now you are dynamically choosing a mater page.
You need to change the MasterUrl property on the SPWeb object representing the site. A good way to do this is to create a SharePoint feature that when activated sets the property, and when deactivated restores the original value. The Feature.xml could look like this:
<?xml version="1.0" encoding="utf-8"?>
<Feature Id="8651CC66-FEB1-4255-B7E9-0DFE24367DAB"
Title="My Master Page"
Scope="Web"
SolutionId="06D3B01F-0C26-457a-BFA5-A1B0BC8D4225"
ReceiverAssembly="MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e95445247029289"
ReceiverClass="MyFeatureReceiver"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="Masterpage.xml"/>
<ElementFile Location="my.master"/>
</ElementManifests>
<Properties>
<Property Key="MyMaster" Value="my.master" />
</Properties>
</Feature>
The file Masterpage.xml uploads your master page to the gallery:
<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="UploadMaster" Url="_catalogs/masterpage" >
<File Url="my.master" Type="GhostableInLibrary" IgnoreIfAlreadyExists="True"/>
</Module>
</Elements>
Include this feature in a WSP solution along with the MyAssembly.dll containing the MyFeatureReceiver class, which goes like this:
public class MyFeatureReceiver : SPFeatureReceiver
{
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = (SPWeb)properties.Feature.Parent;
web.MasterUrl = properties.Definition.Properties["MyMaster"].Value;
web.Update();
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPWeb web = (SPWeb)properties.Feature.Parent;
web.MasterUrl = "default.master";
web.Update();
}
public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
}
}
Finally, deploy the solution and activate the feature on your site(s).

In sharepoint designer's workflow editor how do I get the workflow initiators username?

In Sharepoint designer's workflow editor I wish to retrieve the username/name of the work flow initiator (i.e. who kicked it off or triggered the workflow) - this is relatively easy to do using 3rd party products such as Nintex Workflow 2007 (where I would use something like {Common:Initiator}) - but I can't seem to find any way out of the box to do this using share point designer and MOSS 2007.
Update
It does not look like this rather obvious feature is supported OOTB, so I ended up writing a custom activity (as suggested by one of the answers). I have listed the activities code here for reference though I suspect there are probably a few instances of this floating around out there on blogs as it's a pretty trivial solution:
public partial class LookupInitiatorInfo : Activity
{
public static DependencyProperty __ActivationPropertiesProperty =
DependencyProperty.Register("__ActivationProperties",
typeof(Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties),
typeof(LookupInitiatorInfo));
public static DependencyProperty __ContextProperty =
DependencyProperty.Register("__Context", typeof (WorkflowContext),
typeof (LookupInitiatorInfo));
public static DependencyProperty PropertyValueVariableProperty =
DependencyProperty.Register("PropertyValueVariable", typeof (string),
typeof(LookupInitiatorInfo));
public static DependencyProperty UserPropertyProperty =
DependencyProperty.Register("UserProperty", typeof (string),
typeof (LookupInitiatorInfo));
public LookupInitiatorInfo()
{
InitializeComponent();
}
[Description("ActivationProperties")]
[ValidationOption(ValidationOption.Required)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties __ActivationProperties
{
get { return ((Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties)(base.GetValue(__ActivationPropertiesProperty))); }
set { base.SetValue(__ActivationPropertiesProperty, value); }
}
[Description("Context")]
[ValidationOption(ValidationOption.Required)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public WorkflowContext __Context
{
get { return ((WorkflowContext)(base.GetValue(__ContextProperty))); }
set { base.SetValue(__ContextProperty, value); }
}
[Description("UserProperty")]
[ValidationOption(ValidationOption.Required)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string UserProperty
{
get { return ((string) (base.GetValue(UserPropertyProperty))); }
set { base.SetValue(UserPropertyProperty, value); }
}
[Description("PropertyValueVariable")]
[ValidationOption(ValidationOption.Required)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string PropertyValueVariable
{
get { return ((string) (base.GetValue(PropertyValueVariableProperty))); }
set { base.SetValue(PropertyValueVariableProperty, value); }
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
// value values for the UserProperty (in most cases you
// would use LoginName or Name)
//Sid
//ID
//LoginName
//Name
//IsDomainGroup
//Email
//RawSid
//Notes
try
{
string err = string.Empty;
if (__ActivationProperties == null)
{
err = "__ActivationProperties was null";
}
else
{
SPUser user = __ActivationProperties.OriginatorUser;
if (user != null && UserProperty != null)
{
PropertyInfo property = typeof (SPUser).GetProperty(UserProperty);
if (property != null)
{
object value = property.GetValue(user, null);
PropertyValueVariable = (value != null) ? value.ToString() : "";
}
else
{
err = string.Format("no property found with the name \"{0}\"", UserProperty);
}
}
else
{
err = "__ActivationProperties.OriginatorUser was null";
}
}
if (!string.IsNullOrEmpty(err))
Common.LogExceptionToWorkflowHistory(new ArgumentOutOfRangeException(err), executionContext,
WorkflowInstanceId);
}
catch (Exception e)
{
Common.LogExceptionToWorkflowHistory(e, executionContext, WorkflowInstanceId);
}
return ActivityExecutionStatus.Closed;
}
}
And then wire it up with the following .action xml file:
<?xml version="1.0" encoding="utf-8"?>
<WorkflowInfo Language="en-us">
<Actions>
<Action Name="Lookup initiator user property"
ClassName="XXX.ActivityLibrary.LookupInitiatorInfo"
Assembly="XXX.ActivityLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=XXX"
AppliesTo="all"
Category="WormaldWorkflow Custom Actions">
<RuleDesigner Sentence="Lookup initating users property named %1 and store in %2">
<FieldBind Field="UserProperty" DesignerType="TextArea" Id="1" Text="LoginName" />
<FieldBind Field="PropertyValueVariable" DesignerType="ParameterNames" Text="variable" Id="2"/>
</RuleDesigner>
<Parameters>
<Parameter Name="__Context" Type="Microsoft.Sharepoint.WorkflowActions.WorkflowContext, Microsoft.SharePoint.WorkflowActions" Direction="In"/>
<Parameter Name="__ActivationProperties" Type="Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties, Microsoft.SharePoint" Direction="In"/>
<Parameter Name="UserProperty" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="PropertyValueVariable" Type="System.String, mscorlib" Direction="Out" />
</Parameters>
</Action>
</Actions>
</WorkflowInfo>
For those that google into this article and are now using SharePoint 2010, the workflow initiator variable is now supported OOTB in SharePoint Designer.
The datasource would be "Workflow Context" and the field is, of course, "Initiator" and you can choose to return it as the "Display Name", "Email", "Login Name" or the "User ID Number"
I don't think this is possible to do in SharePoint Designer out of the box. You could probably write a custom action to get the originator, but I don't believe it is exposed through the SPD workflow interface at all.
The best you could probably do is get the user who created or modified the item in the list, but this wouldn't handle cases where the workflow was manually run.
I can think about a simple but not very sophisticated solution for this one by using just SPD. Just in workflow steps create a test item in a secondary list (probably a task list which stores the workflowId and itemId properties for refrence back) and then do a lookup in your workflow on that list to see who is the creator of that item, that value would be the current workflow initiator.
The custom activity solution only work if you are working with moss, if you only have wss 3.0 you can put one step more in your workflow and set a custom comment field with any information, this make the last modified person to change and become the same as the workflow initiator, then you can use the ModifiedBy field to make any decision that you need.

Resources