SharePoint 2010 event receiver,List Item Events, Document library,event ItemAdded not firing - sharepoint-2010

in SharePoint Server 2010 i have a document library and i want to create sub-folders every time a folder created, i have a code snippet but it's not working, i tried to debug but also the event isn't firing, could any one help me please and here is my code:
public class EventReceiver1 : SPItemEventReceiver
{
/// <summary>
/// An item was added.
/// </summary>
private string[] subFolders = new string[] { "sub-folder1", "sub-folder2", "sub folder3" };
public override void ItemAdded(SPItemEventProperties properties)
{
base.ItemAdded(properties);
SPWeb web = properties.OpenWeb();
SPDocumentLibrary ProductsLibrary = (SPDocumentLibrary)web.Lists[properties.ListId];
if (properties.ListItem.ContentType.Name.ToLower() == "new content type" && properties.ListItem.Folder.ParentFolder.ToString() == ProductsLibrary.RootFolder.ToString())
{
string Url = properties.ListItem.ParentList.RootFolder.ServerRelativeUrl.ToString();
SPFolder libFolder = ProductsLibrary.RootFolder.SubFolders[properties.ListItem.Name];
string newFolderUrl = (web.Url + "/" + libFolder.ToString());
foreach (string subfolder in subFolders)
{
SPListItem newSubFolder = ProductsLibrary.Items.Add(newFolderUrl, SPFileSystemObjectType.Folder, subfolder);
newSubFolder.Update();
}
}
}
}
thank you

the solution is to opent the elements.xml and replace the
with the and the code will run perfectly.

Make sure
you have added this event receiver as part of a feature
the feature containing this event receiver is activated
Event wont fire, if you have not followed the above steps

Related

NetOffice - Custom Task Pane in a Appointment window in Outlook

I found out that it's possible to add custom task panes to individual windows like e.g. the appointment with this code snippet:
public void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
Microsoft.Office.Tools.CustomTaskPane myCustomTaskPane;
if(Inspector.CurrentItem is Microsoft.Office.Interop.Outlook.AppointmentItem ) {
UserControl uc1 = MyUserControl();
myCustomTaskPane = getAddIn().CustomTaskPanes.Add(uc1, "MyPanel",Inspector);
myCustomTaskPane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
myCustomTaskPane.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoChange;
myCustomTaskPane.Visible = true;
}
//Additionally You can add a property change listener to the current Item here
}
however, I use 'NetOffice' instead of VSTO to have the add-in compatible with various Outlook versions. And there the add-in doesn't have the CustomTaskPanes property, and the TaskPanes.Add property isn't overloaded to allow adding custom panes on other window than the main explorer.
Ok, worked it out in following way.
In the ComAddin class I have a local variable
Office._CustomTaskPane _taskPane;
and I set the variable on the overriden CTPFactoryAvailable method:
public override void CTPFactoryAvailable(object CTPFactoryInst)
{
_ctpFactory = new NetOffice.OfficeApi.ICTPFactory(this.Application, CTPFactoryInst);
}
Then - when the addin is loaded - I'm adding an event handler to the NewInspectorEvent event:
private void Addin_OnStartupComplete(ref Array custom)
{
var inspectors = Application.Inspectors as NetOffice.OutlookApi.Inspectors;
inspectors.NewInspectorEvent += Inspectors_NewInspectorEvent;
}
In the event handler for creating a new inspector window, I'm creating the pane:
private void Inspectors_NewInspectorEvent(_Inspector Inspector)
{
var ai = Inspector.CurrentItem as AppointmentItem;
if (ai == null)
return;
var ins = Inspector as NetOffice.OutlookApi.Inspector;
_taskPane = _ctpFactory.CreateCTP(typeof(Addin).Assembly.GetName().Name + ".UserControl1", "My title", Inspector);
_taskPane.DockPosition = MsoCTPDockPosition.msoCTPDockPositionTop;
_taskPane.Height = 50;
_taskPane.Visible = true;
}
This draft proof of concept works for me.

RazorEngine Error trying to send email

I have an MVC 4 application that sends out multiple emails. For example, I have an email template for submitting an order, a template for cancelling an order, etc...
I have an Email Service with multiple methods. My controller calls the Send method which looks like this:
public virtual void Send(List<string> recipients, string subject, string template, object data)
{
...
string html = GetContent(template, data);
...
}
The Send method calls GetContent, which is the method causing the problem:
private string GetContent(string template, object data)
{
string path = Path.Combine(BaseTemplatePath, string.Format("{0}{1}", template, ".html.cshtml"));
string content = File.ReadAllText(path);
return Engine.Razor.RunCompile(content, "htmlTemplate", null, data);
}
I am receiving the error:
The same key was already used for another template!
In my GetContent method should I add a new parameter for the TemplateKey and use that variable instead of always using htmlTemplate? Then the new order email template could have newOrderKey and CancelOrderKey for the email template being used to cancel an order?
Explanation
This happens because you use the same template key ("htmlTemplate") for multiple different templates.
Note that the way you currently have implemented GetContent you will run into multiple problems:
Even if you use a unique key, for example the template variable, you will trigger the exception when the templates are edited on disk.
Performance: You are reading the template file every time even when the template is already cached.
Solution:
Implement the ITemplateManager interface to manage your templates:
public class MyTemplateManager : ITemplateManager
{
private readonly string baseTemplatePath;
public MyTemplateManager(string basePath) {
baseTemplatePath = basePath;
}
public ITemplateSource Resolve(ITemplateKey key)
{
string template = key.Name;
string path = Path.Combine(baseTemplatePath, string.Format("{0}{1}", template, ".html.cshtml"));
string content = File.ReadAllText(path);
return new LoadedTemplateSource(content, path);
}
public ITemplateKey GetKey(string name, ResolveType resolveType, ITemplateKey context)
{
return new NameOnlyTemplateKey(name, resolveType, context);
}
public void AddDynamic(ITemplateKey key, ITemplateSource source)
{
throw new NotImplementedException("dynamic templates are not supported!");
}
}
Setup on startup:
var config = new TemplateServiceConfiguration();
config.Debug = true;
config.TemplateManager = new MyTemplateManager(BaseTemplatePath);
Engine.Razor = RazorEngineService.Create(config);
And use it:
// You don't really need this method anymore.
private string GetContent(string template, object data)
{
return Engine.Razor.RunCompile(template, null, data);
}
RazorEngine will now fix all the problems mentioned above internally. Notice how it is perfectly fine to use the name of the template as key, if in your scenario the name is all you need to identify a template (otherwise you cannot use NameOnlyTemplateKey and need to provide your own implementation).
Hope this helps.
(Disclaimer: Contributor of RazorEngine)

Load all Appointment Properties, including extended properties, in Exchange 2010

I'm trying to list all the properties associated with a given calendar appointment, but I can't figure out if there's a way to do it without loading each property individually. Based on some of the code I've seen online, I know I can do something like the following:
/// <summary>
/// List all the properties of an appointment
/// </summary>
public void listProps()
{
Folder myCalendar = Folder.Bind(service, WellKnownFolderName.Calendar);
ItemView view = new ItemView(10);
FindItemsResults<Item> findResults;
do
{
findResults = myCalendar.FindItems(new SearchFilter.IsEqualTo(ItemSchema.ExtendedProperties, MyPropertySetId), view);
service.LoadPropertiesForItems(findResults, new PropertySet(ItemSchema.Subject, ItemSchema.Body));
foreach (Item item in findResults)
{
Console.WriteLine(item.Subject);
Console.WriteLine(item.Body);
}
if (findResults.NextPageOffset.HasValue)
{
view.Offset = findResults.NextPageOffset.Value;
}
} while (findResults.MoreAvailable);
}
However, what I'm really looking for there in the middle is something like this pseudo code:
service.LoadPropertiesForItems(findResults, new PropertySet(*.*));
foreach (Item item in findResults)
{
Console.WriteLine(property)
}
Is this possible?
Thanks!
No, it is not possible.
You can use predefined property sets like: PropertySet.FirstClassProperties to get the known set of properties.
Getting extended properties this way is not supported at all. You have to specify explicitly which extended properties you want to access. For example:
ItemView view = new ItemView(10);
ExtendedPropertyDefinition extendedPropertyDefinition =
new ExtendedPropertyDefinition("Expiration Date", MapiPropertyType.String);
view.PropertySet =
new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.Subject,extendedPropertyDefinition);

SharePoint 2010 Rename Document on Upload Fails in Explorer View

I'm trying to implement a customization in SharePoint 2010 so that when a document is uploaded to a library, the file name is changed to include the Document ID in the name. (I know that people shouldn't worry about file names as much any more, but we have a lot of legacy files already named and users who like to have local copies).
I was able to implement a custom Event Receiver on the ItemAdded event that renames the file by adding the Document ID before the file name. This works correctly from the web Upload.
The problem is with the Explorer View. When I try to add the file using WebDAV in the Explorer View, I get two copies of the file. It seems that when a file is uploaded via the Web the events that fire are
ItemAdding
ItemAdded
But when I copy/paste a file into Explorer View I see the following events:
ItemAdding
ItemAdded
ItemAdding
ItemAdded
ItemUpdating
ItemUpdated
The result is I have two files with different names (since the Document IDs are different).
I've found a lot of people talking about this issue online (this is the best article I found). Anyone have any other ideas? Would it make more sense to do this in a workflow instead of an event receiver? I could use a scheduled job instead, but that might be confusing to the user if the document name changed a few minutes later.
This is my code that works great when using the Web upload but not when using Explorer View:
public override void ItemAdded(SPItemEventProperties properties)
{
try
{
SPListItem currentItem = properties.ListItem;
if (currentItem["_dlc_DocId"] != null)
{
string docId = currentItem["_dlc_DocId"].ToString();
if (!currentItem["BaseName"].ToString().StartsWith(docId))
{
EventFiringEnabled = false;
currentItem["BaseName"] = docId + currentItem["BaseName"];
currentItem.SystemUpdate();
EventFiringEnabled = true;
}
}
}
catch (Exception ex)
{
//Probably should log an error here
}
base.ItemAdded(properties);
}
I have found that using a Visual Studio workflow allows me the most flexibility to do this. A SharePoint Designer Workflow would be simpler, but would be harder to deploy to different sites and libraries.
After reading some good articles including this and this I have come up with this code which seems to work. It starts a workflow and waits until the document is not in a LockState and then processes the filename.
The workflow looks like this:
And here is the code behind:
namespace ControlledDocuments.RenameWorkflow
{
public sealed partial class RenameWorkflow : SequentialWorkflowActivity
{
public RenameWorkflow()
{
InitializeComponent();
}
public Guid workflowId = default(System.Guid);
public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();
Boolean continueWaiting = true;
private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e)
{
CheckFileStatus();
}
private void whileActivity(object sender, ConditionalEventArgs e)
{
e.Result = continueWaiting;
}
private void onWorkflowItemChanged(object sender, ExternalDataEventArgs e)
{
CheckFileStatus();
}
private void CheckFileStatus()
{
if (workflowProperties.Item.File.LockType == SPFile.SPLockType.None)
{
continueWaiting = false;
}
}
private void renameFile(object sender, EventArgs e)
{
try
{
SPListItem currentItem = workflowProperties.Item;
if (currentItem["_dlc_DocId"] != null)
{
string docId = currentItem["_dlc_DocId"].ToString();
if (!currentItem["BaseName"].ToString().StartsWith(docId))
{
currentItem["BaseName"] = docId + currentItem["BaseName"];
currentItem.SystemUpdate();
}
}
}
catch (Exception ex)
{
//Should do something useful here
}
}
}
}
Hope this helps someone else if they have the same problem.
Well i'd go for the workflow workaround... there are 2 options imo:
1) Create a boolean fied in your document library, then create a SPD workflow that fires when the item is added and set that field to "Changed" or something. In the EventReceiver you then check whether that field has been set..
2) Do everything with the SPD workflow - changing the title like in this example should be no problem.

Sharepoint 2010 Event receiver not firing for subsite

I have an event receiver (WebAdding and WebProvisioned) which works just fine for sites created off the root of the site collection. However, subsites (for example, teamsites created within other areas) do not trigger the code at all.
Does anyone have any idea as to why?
using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
using System.Text;
namespace TestEventReceiver.EventReceiver1
{
/// <summary>
/// Web Events
/// </summary>
public class EventReceiver1 : SPWebEventReceiver
{
/// <summary>
/// A site is being provisioned.
/// </summary>
public override void WebAdding(SPWebEventProperties properties)
{
base.WebAdding(properties);
using (SPWeb web = properties.Web)
{
StringBuilder output = new StringBuilder();
output.AppendFormat("Web Adding");
output.AppendFormat("<br>Web title: {0}",web.Title);
SendMyEmail(web, "SendItToMe#MyTestAddress.com", "Web Adding", output.ToString());
}
}
/// <summary>
/// A site was provisioned.
/// </summary>
public override void WebProvisioned(SPWebEventProperties properties)
{
base.WebProvisioned(properties);
using (SPWeb web = properties.Web)
{
StringBuilder output = new StringBuilder();
output.AppendFormat("Web Provisioned");
output.AppendFormat("<br>Web title: {0}", web.Title);
SendMyEmail(web, "SendItToMe#MyTestAddress.com", "Web Provisioned", output.ToString());
}
}
private void SendMyEmail(SPWeb Web, String toAddress, String subject, String message)
{
bool appendHtmlTag = false;
bool htmlEncode = true;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPUtility.SendEmail(Web, appendHtmlTag, htmlEncode, toAddress, subject, message);
});
}
}
}
Thanks in advance,
Matt
I think you should not be using 'Using' .
The SPWeb object reference you get is from properties.Web which is being passed to the WebAdding method. You will run into issues because of this.
Have a look at how your event receiver is provisioned - it may be the scope needs to be changed to Site rather than Web. Perhaps you could post here so we can see.
On my site I had the same issue. Still figuring out the xml files, but in my Elements.xml file for the Receivers, each receiver had the same sequence number. Once I made them unique within the Elements.xml file, the WebProvisioned event started firing. Don't know if this is the same issue you were having.
This code is showing the WebAdding event and that event is occurring on the parent Web.
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spwebeventreceiver.webadding.aspx
Try to change scope of your receiver (in Elements.xml file add attribute ). Also, make sure that the feature of your Event receiver is activated in you site features in the subsite.