right now, I'm using the SPSecurity.RunWithElevatedPrivileges method to let anonymous users add list items to a list. What i would like to do is make a general method that takes a Site, List and List item as an argument and adds the item to the list being passed. Right now I have :
public static void AddItemElevated(Guid siteID, SPListItem item, SPList list)
{
SPSite mySite = SPContext.Current.Site;
SPList myList = WPToolKit.GetSPList(mySite, listPath);
SPWeb myWeb = myList.ParentWeb;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite eleSite = new SPSite(mySite.ID))
{
using (SPWeb eleWeb = eleSite.OpenWeb(myWeb.ID))
{
eleWeb.AllowUnsafeUpdates = true;
SPList eleList = eleWeb.Lists[myList.Title];
SPListItem itemToAdd = list.Items.Add();
itemToAdd = item;
itemToAdd.Update();
eleWeb.AllowUnsafeUpdates = false;
}
}
});
}
The problem is that 'item' gets initialized outside of the elevated privileges so when 'itemToAdd' is set to 'item' it loses its elevated privileges, causing the code to break at 'item.update()' if used my an non-privileged user.
Any Thoughts?
The problem could be because you are passing in your list. Try just passing in the list name and then grabbing the list from the elevated web like this:
public static void AddItemElevated(SPListItem itemToAdd, string listName)
{
SPWeb web = SPContext.Current.Web;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite elevatedSite = new SPSite(web.Url))
{
using (SPWeb elevatedWeb = elevatedSite.OpenWeb())
{
elevatedWeb.AllowUnsafeUpdates = true;
SPList list = elevatedWeb.Lists[listName];
SPListItem item = list.Items.Add();
item = itemToAdd;
item.Update();
elevatedWeb.AllowUnsafeUpdates = false;
}
}
}
}
Following line itemToAdd = item; does something strange - you adding item to one list (with list.Items.Add() ) but updating item from another list/location (one that comes as argument).
Not sure what you actually want, but maybe you want to co copy all fileds from item to itemToAdd. Consider in this case to pass fieldName/value pairs as argument to make it clear that you are adding new item with given values.
Note, that anonymous users are able to add items to lists that explicitly allow it.
I haven't tried it but possibly this could help - http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splistitem.copyto.aspx
Regards,
Nitin Rastogi
If item is coming from an SPList.AddItem() method, the splist instance must be get from an elevated web. otherwise this code will always break for anonymous users.
or you can allow anonymous user to add item to list, so you won't need running the code with elevated privileges.
by the way, itemToAdd = item; is not a correct way of setting the new added item to an old instance.
Related
I have tried to make a simple console application that retrieves list items from Share Point Online. It works fine when I retrieve list of the sites or list titles from the site, but I receive no list items when I try to get it from the particular list.
I've listed many examples of similar tasks and almost all of them were written in the same way. That's why I don't exclude that the reason of my case might be in an insufficient permissions (I attach a screenshot of the API permissions).
Please, check my code and permissions. Any help will be highly appreciated.
Application code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using SP = Microsoft.SharePoint.Client;
namespace SharePointTrigger
{
class Program
{
static async Task Main(string[] args)
{
Uri site = new Uri("https://MyCompany.sharepoint.com/sites/MyProject");
string user = $"ServiceUser#MyCompany.com";
string rawPassword = $"password";
SecureString password = new SecureString();
foreach (char c in rawPassword) password.AppendChar(c);
using (var authenticationManager = new AuthenticationManager()) //HELPER CLASS TO OBTAIN ACCESS TOKEN
using (var context = authenticationManager.GetContext(site, user, password))
{
//RETRIVING LIST TITLE - WORKS FINE
/*
Web web = context.Web;
context.Load(web.Lists,
lists => lists.Include(list => list.Title,
list => list.Id));
context.ExecuteQuery();
foreach (SP.List list in web.Lists)
{
Console.WriteLine(list.Title);
}
*/
//RETRIVING LIST ITEM
Web myWeb = context.Web;
SP.List myList = myWeb.Lists.GetByTitle("List_of_Items");
SP.ListItemCollection listItemCollection = myList.GetItems(CamlQuery.CreateAllItemsQuery());
context.Load(listItemCollection,
eachItem => eachItem.Include(
item => item,
item => item["Title"],
item => item["ID"]
)
);
context.ExecuteQuery();
foreach (SP.ListItem listItem in listItemCollection)
{
Console.WriteLine("ID: " + listItem["ID"].ToString() + "Title: " + (string)listItem["Title"].ToString());
}
Console.ReadKey();
}
}
}
}
API permissions
API permissions
It doesn't look like permission issue on checking your app permissions or Code issue.
However, looking at the below line :
SP.ListItemCollection listItemCollection = myList.GetItems(CamlQuery.CreateAllItemsQuery());
You are trying to bring in all the items.
A similar behavior is observed of returning the empty items when the list is a very large list (>5000 or more than 12 lookup columns) or the list hits a list threshold)
If you are falling on the above scenario - you could create a index and filter the items.
You can use CAML query to filter the items instead of trying to fetch all the items in a single go !
Reference for CAML query :
https://techcommunity.microsoft.com/t5/sharepoint/filtering-list-item-using-caml-query-in-sharepoint/m-p/1415904
https://sharepoint.stackexchange.com/questions/94631/filtering-list-using-caml-query-and-binding-it-to-dropdown-in-c
Also, I would check whether the items have a item level permission.
List settings -> Advanced Settings
Ideally, you should not encounter this issue because of the above, however this settings increases number of the scopes and may cause to hit the threshold sooner because.
I have Sharepoint enterprise server with list that have "Everyone" user grant as contributor
but, when I execute below code with authenticated user (let say, user Abc), for add item list row, the row never added to list
SPWeb web1 = SPContext.Current.Web;
using (SPSite site = new SPSite(web1.Url))
{
using (SPWeb web = site.OpenWeb())
{
SPList roomList = web.Lists.TryGetList(LIST_NAME);
if (roomList != null)
{
SPListItem newItem = roomList.Items.Add();
PopulateListWithData(data, ref newItem);
newItem.Update();
}
}
}
}
How can I add row to list with user Abc?
try to add using following code
using (SPSite site = new SPSite(SPContext.Current.Site.Url))
{
using (SPWeb web = site.OpenWeb(SPContext.Current.Web))
{
SPList roomList = web.Lists.TryGetList(LIST_NAME);
if (roomList != null)
{
SPListItem newItem = roomList.AddItem();
PopulateListWithData(data, ref newItem);
newItem.Update();
}
}
}
if you still have the same issue
try to ensure the following
list you try to add to already exists in root web site
List name is types right because your code may be break after TryGetList
after that if still have the same issue you need to debug or check sharepoint logs to catch exception that happen
I created web part (something like wizard) and need change item value in list, but when get list item, they haven't items (logged user haven't access to this list). Can I ignore sharepoint permission, and update this value?
I use LINQ to sharepoint and get context:
using (SystemOcenContextDataContext ctx = new SystemOcenContextDataContext("http://sh2010/sites/270"))
{
// code :)
}
Update:
make test when get list using:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite ElevatedSite = new SPSite("http://sh2010/sites/270"))
{
using (SPWeb ElevatedWeb = ElevatedSite.OpenWeb())
{
list = ElevatedWeb.Lists["Ankiety i oceny"];
}
}
});
the object list "have" items
but in my project I use sharepoint linq datacontext when using:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SystemOcenContextDataContext ctx = new SystemOcenContextDataContext("http://sh2010/sites/270"))
{
item = ctx.AnkietyIOceny.First();
}
});
the context(ctx) didn't have any items :/
any idea?
SPSecurity.RunWithElevatedPrivileges(delegate()
{
// Pur your code here.
});
Get more details Here
The SharePoint linq provides doesn't work with ElevatedPrivileges. It accesses the SPWeb.Current instance which will have the access rights of the request and not the elevated user.
http://jcapka.blogspot.com/2010/05/making-linq-to-sharepoint-work-for.html
There's a work around, which I've implemented generally the same thing. It's a big awkward but it works as far as I can tell.
I have an Image List on each and every web (SPWeb) of a SiteCollection. I want to set a specific property of this List. I am iterating through all the Sites withing a SiteCollection and finding the List and setting its properties. My problem is that I can set the properties of a List present at first level Sites, but can't set the properties of Lists, present at 2nd or 3rd level Sites. For example,
Here is site hierarchy:
Home (Rootweb) 1st level
Home-> Aboutus (subsite) 2nd level
Home->Aboutus->Our Mission (subsite) 3rd level
here is the code for that!
using (SPSite oSPsite = new SPSite(http://spdev/))
{
foreach (SPWeb web in oSPsite.AllWebs)
{
SPList list = web.GetList("PublishingImages");
if (list != null)
{
foreach (SPContentType contentType in list.ContentTypes)
{
if (contentType.Name == "Publishing Picture")// but id is better
{
list.EnableModeration = false;
list.Update();
}
}
}
web.Dispose();
}
}
Is it because I'm disposing the parent first?
Assuming the list name is the same on every site (PublishingImages) and you're on WSS 3.0 or MOSS07 here is the sample code:
using (SPSite oSPsite = new SPSite("yourSiteUrlHere"))
{
SPWebCollection siteWebs = oSPsite.AllWebs;
foreach (SPWeb web in siteWebs)
{
try
{
SPList list = null;
try
{
list = web.Lists["PublishingImages"];
}
catch {}
if (list != null)
{
// todo: update list properties here
list.Update();
}
}
finally
{
if(web != null)
web.Dispose();
}
}
}
As Ashutosh mentioned, there are some properties that don't work on all list types but I'm assuming since you've already stated it works on some of them you aren't setting any of those.
I am really looking for either a small code snippet.
I have a C# console app that I will use to somehow add list items to my custom list. I have created a custom content type too. So not sure if I need to create an C# class from this content type too. Perhaps not.
I think these both blog post should help you solving your problem.
http://blog.the-dargans.co.uk/2007/04/programmatically-adding-items-to.html
http://asadewa.wordpress.com/2007/11/19/adding-a-custom-content-type-specific-item-on-a-sharepoint-list/
Short walk through:
Get a instance of the list you want to add the item to.
Add a new item to the list:
SPListItem newItem = list.AddItem();
To bind you new item to a content type you have to set the content type id for the new item:
newItem["ContentTypeId"] = <Id of the content type>;
Set the fields specified within your content type.
Commit your changes:
newItem.Update();
To put it simple you will need to follow the step.
You need to reference the Microsoft.SharePoint.dll to the application.
Assuming the List Name is Test and it has only one Field "Title" here is the code.
using (SPSite oSite=new SPSite("http://mysharepoint"))
{
using (SPWeb oWeb=oSite.RootWeb)
{
SPList oList = oWeb.Lists["Test"];
SPListItem oSPListItem = oList.Items.Add();
oSPListItem["Title"] = "Hello SharePoint";
oSPListItem.Update();
}
}
Note that you need to run this application in the Same server where the SharePoint is installed.
You dont need to create a Custom Class for Custom Content Type
You can create an item in your custom SharePoint list doing something like this:
using (SPSite site = new SPSite("http://sharepoint"))
{
using (SPWeb web = site.RootWeb)
{
SPList list = web.Lists["My List"];
SPListItem listItem = list.AddItem();
listItem["Title"] = "The Title";
listItem["CustomColumn"] = "I am custom";
listItem.Update();
}
}
Using list.AddItem() should save the lists items being enumerated.
This is how it was on the Microsoft site, with me just tweaking the SPSite and SPWeb since these might vary from environment to environment and it helps not to have to hard-code these:
using (SPSite oSiteCollection = new SPSite(SPContext.Current.Site.Url))
{
using (SPWeb oWeb = oSiteCollection.OpenWeb(SPContext.Current.Web))
{
SPList oList = oWeb.Lists["Announcements"];
// You may also use
// SPList oList = oWeb.GetList("/Lists/Announcements");
// to avoid querying all of the sites' lists
SPListItem oListItem = oList.Items.Add();
oListItem["Title"] = "My Item";
oListItem["Created"] = new DateTime(2004, 1, 23);
oListItem["Modified"] = new DateTime(2005, 10, 1);
oListItem["Author"] = 3;
oListItem["Editor"] = 3;
oListItem.Update();
}
}
Source:
SPListItemClass (Microsoft.SharePoint). (2012). Retrieved February 22, 2012, from http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splistitem.aspx.
I had a similar problem and was able to solve it by following the below approach (similar to other answers but needed credentials too),
1- add Microsoft.SharePointOnline.CSOM by tools->NuGet Package Manager->Manage NuGet Packages for solution->Browse-> select and install
2- Add "using Microsoft.SharePoint.Client; "
then the below code
string siteUrl = "https://yourcompany.sharepoint.com/sites/Yoursite";
SecureString passWord = new SecureString();
var password = "Your password here";
var securePassword = new SecureString();
foreach (char c in password)
{
securePassword.AppendChar(c);
}
ClientContext clientContext = new ClientContext(siteUrl);
clientContext.Credentials = new SharePointOnlineCredentials("Username#domain.nz", securePassword);/*passWord*/
List oList = clientContext.Web.Lists.GetByTitle("The name of your list here");
ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
ListItem oListItem = oList.AddItem(itemCreateInfo);
oListItem["PK"] = "1";
oListItem["Precinct"] = "Mangere";
oListItem["Title"] = "Innovation";
oListItem["Project_x0020_Name"] = "test from C#";
oListItem["Project_x0020_ID"] = "ID_123_from C#";
oListItem["Project_x0020_start_x0020_date"] = "2020-05-01 01:01:01";
oListItem.Update();
clientContext.ExecuteQuery();
Remember that your fields may be different with what you see, for example in my list I see "Project Name", while the actual value is "Project_x0020_ID". How to get these values (i.e. internal filed values)?
A few approaches:
1- Use MS flow and see them
2- https://mstechtalk.com/check-column-internal-name-sharepoint-list/ or https://sharepoint.stackexchange.com/questions/787/finding-the-internal-name-and-display-name-for-a-list-column
3- Use a C# reader and read your sharepoint list
The rest of operations (update/delete):
https://learn.microsoft.com/en-us/previous-versions/office/developer/sharepoint-2010/ee539976(v%3Doffice.14)