i have a sharepoint problem. I have an event handler on a list and whenever someone adds a new item in the list I want to create a new web with the required details. The problem comes when a diferent user that is not site collection admin adds the item. On the Web.Webs.Add() method i get the error:
Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)).
Note that I'm using the SPSecurity.RunWithElevatedPrivileges delegate.
Here is a code sample:
public override void ItemAdded(SPItemEventProperties properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
string url = "the url";
if (Array.IndexOf(properties.Web.Webs.Names, url) >= 0)
{
properties.Web.Webs.Delete(url);
}
SPWeb newWeb = properties.Web.Webs.Add(url, "title", "description", properties.Web.Language, "STS#1", false, false);
});
}
Thanks.
I got it. The problem was that the web I was calling was not elevated, so I did somting like this:
public override void ItemAdded(SPItemEventProperties properties)
{
SPWeb web = properties.Web;
SPListItem currentItem= properties.ListItem;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(web.Site.ID))
{
using (SPWeb elevWeb = site.OpenWeb(web.ID))
{
SPList elevList = ListUtils.GetList(elevWeb, "list");
SPListItem elevItem = elevList.Items[currentItem.UniqueId];
elevWeb.AllowUnsafeUpdates = true;
string url = "the url";
if (Array.IndexOf(elevWeb.Webs.Names, url) >= 0)
{
elevWeb.Webs.Delete(url);
}
SPWeb newWeb = elevWeb.Webs.Add(url, "title", "description", elevWeb.Language, "STS#1", false, false);
}
}
});
}
Related
I created an event receiver that should trigger a SharePoint designer workflow, however this never happens. This part of the code never evaluates to true for the guid and workflow association: if (association.BaseId == workflowGuid). I am a bit stumped and not quite sure why it's not working. Any insight would be appreciated...and my code is below. Basically when an item is added to my list, it should trigger my Sharepoint designer workflow but this never happens and I can manually start the workflow fine.
public override void ItemAdded(SPItemEventProperties properties)
{
base.ItemAdded(properties);
startWF(properties);
}
private void startWF(SPItemEventProperties properties)
{
try
{
//bool startWF = false;
string strWorkflowID = "{c66ff94f-ba7c-4495-82fe-e73cdd18bad9}";
//string statusVal = properties.AfterProperties["eRequest Division"].ToString();
SPListItem li = properties.ListItem;
//using (SPWeb web = li.Web)
using (SPWeb web = properties.OpenWeb())
{
using (SPSite site = web.Site)
{
SPWorkflowManager mgr = site.WorkflowManager;
SPList parentList = li.ParentList;
//SPList list = web.Lists["Charitable and Political"];
SPWorkflowAssociationCollection associationCollection = parentList.WorkflowAssociations;
LookUpAndStart(li, mgr, associationCollection, "{c66ff94f-ba7c-4495-82fe-e73cdd18bad9}");
}
}
}
catch (Exception ex)
{
}
}
private static void LookUpAndStart(SPListItem listItem, SPWorkflowManager mgr, SPWorkflowAssociationCollection associationCollection, string workflowID)
{
foreach (SPWorkflowAssociation association in associationCollection)
{
Guid workflowGuid = new Guid(workflowID);
//if (association.Name.ToLower().Equals(workflowGuid))
//if (association.BaseId == workflowGuid)
//if (association.BaseId.ToString("B").Equals(workflowGuid))
if (association.BaseId == workflowGuid)
{
string data = association.AssociationData;
SPWorkflow wf = mgr.StartWorkflow(listItem, association, data, true);
break;
}
}
}
}
}
In my case the following was the problem.
Declarative workflows will not start automatically if the following conditions are true:
The Windows SharePoint Services Web application runs under a user's domain account.
The user logs in by using this domain account.
The site displays the user name as System Account.
In an EventReceiver I call this method GetPernNr on Item Added:
public override void ItemAdded(SPItemEventProperties properties)
{
SPSite site = properties.Web.Site;
using (SPWeb currentWeb = site.OpenWeb(properties.Web.ID))
{
.....
perNr = UserProfileUtils.GetPernNr(currentWeb, assignedTo.ToString());
.....
}
}
where assignedTo is a SPUser.
public static string GetPernNr(SPWeb web, string accountName)
{
string perNr = string.Empty;
UserProfile upUser = null;
try
{
PermissionSet ps = new PermissionSet(System.Security.Permissions.PermissionState.Unrestricted);
ps.Assert();
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite siteColl = new SPSite(web.Site.ID))
{
SPServiceContext serviceContext = SPServiceContext.GetContext(siteColl);
UserProfileManager upm = new UserProfileManager(serviceContext);
if (upm.UserExists(accountName))
{
upUser = upm.GetUserProfile(accountName);
if (upUser["PersonNumber"] != null)
{
perNr = upUser["PersonNumber"].Value.ToString();
}
}
}
});
}
catch (Exception ex)
{
..
}
finally { System.Security.CodeAccessPermission.RevertAssert(); }
return perNr;
}
It's strange, this code works when I try to get value from a default field in UserProfile (Office, Manager, etc). And also works when I call this method outside EventReceiver, but in my case, upUser["PersonNumber"].Value returns null.
Any help will be much appreciated
Did you check the custom property permission in the central admin.
Central Administration -> Edit User Profile Property -> Policy Settings
Make default privacy policy to everyone and then try.
Here is the steps for SharePoint Server 2013:
Central Admin > Application Management > Manage service applications > Your User Profile Application > Manage User
Properties
Select Edit option from property menu.
Now Under "Policy Settings":
Set Default Privacy Setting: Everyone
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
webpart is working on local server but not working on production server when "SPSite" class is uesd in the web part. On the production server it throws error. If I do not use that class in the webpart the web part also works on live machine.
Any idea what might be causing the error?
the code in the webpart is this:
namespace CompanyNews
{
[Guid("40de3c60-9e30-4050-b9f3-01e71868f522")]
public class CompanyNews : System.Web.UI.WebControls.WebParts.WebPart
{
private HtmlTextWriter writer;
public CompanyNews()
{
}
protected override void RenderContents(HtmlTextWriter writer)
{
base.RenderContents(writer);
using (SPSite site = SPContext.Current.Site)
{
using (SPWeb web = site.OpenWeb())
{
string listName = "News Display";
writer.Write(listName);
SPList list = null;
foreach (SPList currentList in web.Lists)
{
if (currentList.Title.Equals(listName,
StringComparison.InvariantCultureIgnoreCase))
{
list = currentList;
break;
}
}
writer.WriteBeginTag("ul");
foreach (SPListItem item in list.Items)
{
writer.Write("<li style=\"font-size:12px;padding:1px\">");
writer.Write(item["Title"].ToString() + "... ");
writer.Write("<a class=\"smallerred\" href=\"#\">Read More</a>");
writer.Write("</li>");
}
writer.WriteEndTag("ul");
}
}
}
}
}
The dll of the webpart is in the bin folder and in the web.config file there is an entry for the web par as a safe control.
Other webpart which displays a "hellow world" message is also uploaded to production the same way.
I i guess its the code that is causing the problem.
The error message is: "An error occurred while previewing the web part"
just something I noticed, you shouldn't wrap objects from the Current Context in a using statement. Good article here Clicky
Better practice would be to use the following
using (SPSite mySite = new SPSite(SPContext.Current.Site.Url))
{
...
}
Also you should look at packaging up your solution in a WSP, allowing stsadm to deploy it. Dragging into the GAC isn't very good practice.
Shane
The SPSite object isn't getting reference anywhere that I can see. Why don't you remove it anyway as it's superflous to your needs?
SPWeb web = SPContext.Current.Web;
string listName = "News Display";
writer.Write(listName);
SPList list = null;
foreach (SPList currentList in web.Lists)
{
if (currentList.Title.Equals(listName,
StringComparison.InvariantCultureIgnoreCase))
{
list = currentList;
break;
}
}
writer.WriteBeginTag("ul");
foreach (SPListItem item in list.Items)
{
writer.Write("<li style=\"font-size:12px;padding:1px\">");
writer.Write(item["Title"].ToString() + "... ");
writer.Write("<a class=\"smallerred\" href=\"#\">Read More</a>");
writer.Write("</li>");
}
writer.WriteEndTag("ul");
Using the following block of code, the listItem.Update fails with a NullReferenceException:
SPWeb web = null;
SPList list = null;
SPListItem listItem = null;
try
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(this.SiteUrl))
{
web = site.OpenWeb();
list = web.Lists[this.ListName];
listItem = list.Items.Add();
listItem["Background"] = "foo";
}
}
);
listItem.Update();
}
catch
{
}
finally
{
web.Dispose();
}
If I move the listItem.Update() method inside of the anonymous delegate, I get "Operation is not valid due to the current state of the object."
Yes, I've combed through SO and have tried many permutations without success.
Any ideas?
Update:
After the first comment, I tried to remove the anonymous delegate from the code to see if it fared any better:
// store the selected item to pass between methods
public T SelectedItem { get; set; }
// set the selected item and call the delegate method
public virtual void Save(T item)
{
SelectedItem = item;
try
{
SPSecurity.RunWithElevatedPrivileges(SaveSelectedItem);
}
catch
{
}
}
public virtual void SaveSelectedItem()
{
if (SelectedItem != null)
{
using (SPSite site = new SPSite(this.SiteUrl))
{
using(SPWeb web = site.OpenWeb())
{
SPList list = web.Lists[this.ListName];
SPListItem listItem = list.Items.Add();
//UpdateListItem(listItem, SelectedItem);
listItem["Background"] = "foo";
listItem.Update();
}
}
}
}
And this still fails "Operation is not valid due to the current state of the object." In both code samples, it looks like site.Impersonating is false. I am using Windows Auth, and Impersonation in the web.config. This is running from the ASP.Net Development server.
I found an example from this site (blackninjasoftware). I create a reference to the site, grab its SystemAccount token and then create another reference to the site, using the admin token. It seemed a little hackish to me at first - but hey - I have a deadline.
Final working method body now looks like:
SPListItem new_item = null;
SPSite initialSite = new SPSite(this.SiteUrl);
using (var site = new SPSite(this.SiteUrl, initialSite.SystemAccount.UserToken))
{
// This code runs under the security context of the SHAREPOINT\system
// for all objects accessed through the "site" reference. Note that it's a
// different reference than SPContext.Current.Site.
using (var elevatedWeb = site.OpenWeb())
{
elevatedWeb.AllowUnsafeUpdates = true;
SPList list = elevatedWeb.Lists[this.ListName];
new_item = list.Items.Add();
UpdateListItem(new_item, item);
if (new_item != null)
{
new_item.Update();
}
}
}
initialSite.Dispose();