'Activate Features': Object reference not set to an instance of an object - c#

I have the following activation code:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
// Create a new list and populate it.
using (SPWeb web = properties.Feature.Parent as SPWeb)
{
web.Lists.Add("Projects", "Projects That are currently being worked on.", SPListTemplateType.GenericList);
web.Update();
// Add the new list and the new content.
SPList projectList = web.Lists["Projects"];
projectList.Fields.Add("Name", SPFieldType.Text, false);
projectList.Fields.Add("Description", SPFieldType.Text, false);
projectList.Update();
//Create the view? - Possibly remove me.
System.Collections.Specialized.StringCollection stringCollection =
new System.Collections.Specialized.StringCollection();
stringCollection.Add("Name");
stringCollection.Add("Description");
//Add the list.
projectList.Views.Add("Project Summary", stringCollection, #"", 100,
true, true, Microsoft.SharePoint.SPViewCollection.SPViewType.Html, false);
projectList.Update();
}
}
Which should go through and add a new list called project and its associated view. How ever when running the app I get:
'Activate Features': Object reference not set to an instance of an
object
My questions are:
Why is this happening? The activation happens at a site level. and I am the admin of the "development" site.
Should I be checking each time to make sure this list doesn't already exist? (each time, referring to each time I hit deploy)

I'm going to assume that you have a Site scoped feature and that your NullReferenceException is being caused by you attempting to cast properties.Feature.Parent as SPWeb.
If my assumption about your feature being Site scoped is correct you can't get access to an SPWeb the way you are trying. Try this instead:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSite siteCollection = properties.Feature.Parent as SPSite;
if (siteCollection != null)
{
SPWeb web = siteCollection.RootWeb;
// Rest of your code here.
}
}

Related

Sharepoint 2013 On-Premises C# CSOM Cross Site Collection List Access

I see this has sorta been asked a bunch times before, but all the examples I am running across will not work or are in JavaScript , I NEED HELP WITH C# please.
I have a farm with server site collections on it, I successfully created a provider hosted addin/App, When it trys to access lists on the Web that launched it everything is fine! I need to try to access lists on other webs in the same farm and on the same domain does anyone have an example of C# code that can do this
You can create a repository method like this:
public class SharepointRepository
{
public ListItemCollection ListTopN(string urlSite, string listName, bool ascending, string column, int rowLimit)
{
using (var context = new ClientContext(urlSite))
{
context.Credentials = CredentialCache.DefaultCredentials;
List list = context.Web.Lists.GetByTitle(listName);
string myQuery = string.Format("<View><Query><OrderBy><FieldRef Name='{0}' Ascending='{1}' /></OrderBy></Query><RowLimit>{2}</RowLimit></View>", column, ascending.ToString(), rowLimit);
CamlQuery query = new CamlQuery();
query.ViewXml = myQuery;
ListItemCollection collection = list.GetItems(query);
context.Load(list);
context.Load(collection);
context.ExecuteQuery();
return collection;
}
}
}
this approach uses the managed csom.
and if you are facing problems with ADFS, try adding after this line
context.Credentials = CredentialCache.DefaultCredentials;
this
context.ExecutingWebRequest += new EventHandler<WebRequestEventArgs>(MixedAuthRequestMethod);
and this function
void MixedAuthRequestMethod(object sender, WebRequestEventArgs e)
{
e.WebRequestExecutor.RequestHeaders.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
}
This is a basic referente:
https://msdn.microsoft.com/en-us/library/office/fp179912.aspx
You should also look at the Sharepoint App Model and the Rest OData API.
I figured this out, so I am posting it just in case someone else needs it, also please understand that I am total noob to SharePoint and this may not be the best way or even the SharePoint Accepted way of doing things.
First you need to give you app Tenant Permission (Full Control or Manage) ! - Very Important
Second I created this function that make a n SharePoint Context to a site other then the one the app is running on
public ClientContext CreateRemoteSharePointContext(string TargetWebURL, SharePointContext CurrentSharePointContext)
{
//In order for us to create a share point client context that points to
//site other then the site that this app is running we need to copy some url parameters from the current
//context. These parameters are found on the current share-point context
NameValueCollection QueryString = Request.QueryString;
//Since, The Query string is a read only collection, a use of reflection is required to update the
//values on the request object, we must use the current request object because it contains
//security and other headers/cookies that we need for the context to be created, Grab the url params that we need
//other then TargetWebUrl, that will be the url of the site we want to manipulate
Utility.AddToReadonlyQueryString(QueryString, "SPHostUrl", CurrentSharePointContext.SPHostUrl.ToString(), System.Web.HttpContext.Current.Request);
Utility.AddToReadonlyQueryString(QueryString, "SPAppWebUrl", TargetWebURL, System.Web.HttpContext.Current.Request);
Utility.AddToReadonlyQueryString(QueryString, "SPLanguage", CurrentSharePointContext.SPLanguage, System.Web.HttpContext.Current.Request);
Utility.AddToReadonlyQueryString(QueryString, "SPClientTag", CurrentSharePointContext.SPClientTag, System.Web.HttpContext.Current.Request);
Utility.AddToReadonlyQueryString(QueryString, "SPProductNumber", CurrentSharePointContext.SPProductNumber, System.Web.HttpContext.Current.Request);
//This is a special line, we need to get the AppOnly access token and pass it along to the target site, its is a little counter intuitive
//Because we are using TokenHelper.GetS2SAccessToeknWithWindowsIdentity - but we pass NULL as the User identity, this will
//check the app manifest and if the app has a CERT and AppOnly Permission it will return a valid app only token to use
Utility.AddToReadonlyQueryString(QueryString, "AppContextToken", TokenHelper.GetS2SAccessTokenWithWindowsIdentity(new Uri(TargetWebURL), null), System.Web.HttpContext.Current.Request);
//Return the newly created context
return SharePointContextProvider.Current.CreateSharePointContext(HttpContext.Request, TargetWebURL).CreateAppOnlyClientContextForSPAppWeb();
}
As you can see the I had to kinda hack up the Querystring and grab some values so here is the Utility class that does that :
public class Utility
{
public static void UpdateReadonlyQueryString(NameValueCollection collectionToUpdate, string paramName, string paramValue, HttpRequest Request)
{
collectionToUpdate = (NameValueCollection)Request.GetType().GetField("_queryString", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Request);
PropertyInfo readOnlyInfo = collectionToUpdate.GetType().GetProperty("IsReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
readOnlyInfo.SetValue(collectionToUpdate, false, null);
collectionToUpdate[paramName] = paramValue;
readOnlyInfo.SetValue(collectionToUpdate, true, null);
}
public static void AddToReadonlyQueryString(NameValueCollection collectionToUpdate, string paramName, string paramValue, HttpRequest Request)
{
collectionToUpdate = Request.QueryString;
collectionToUpdate = (NameValueCollection)Request.GetType().GetField("_queryString", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Request);
PropertyInfo readOnlyInfo = collectionToUpdate.GetType().GetProperty("IsReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
readOnlyInfo.SetValue(collectionToUpdate, false, null);
collectionToUpdate.Add( paramName, paramValue);
readOnlyInfo.SetValue(collectionToUpdate, true, null);
}
}
and Finally the SharePoint access code the looks like much of the same SharePoint code out there on the web, I had to remove some stuff from it that would identify the project or who its for, but it should be easy to pick out what you need from in side
try
{
//Get the name of the sharepoint list that needs to be updated from settings
var ListName = ConfigurationManager.AppSettings[Constants.SettingsConstants.SPLaunchQueList];
var TargetSiteToUpdate = "URL TO THE SITE YOUR TRYING TO UPDATE";
//Get the sharepoint context from session
var spContext = <SOME HOW CREATE YOUR CONTEXT>
//Lets create a client context from the current sharepoint context to the target site
//NOTE this requires the application to HAVE Tenant level permission, it must be trusted by
//the farm admin
using (var spClientContext = CreateRemoteSharePointContext(TargetSiteToUpdate, spContext))
{
//Get the current Web (Sharepoint Web) from the client context
var web = spClientContext.Web;
//Load all the webs properties including title , url all the lists and get the subwebs if any as well
spClientContext.Load(web, x => x.Title, x => x.Url, x => x.Lists, x => x.Webs.Include(w => w.Title, w => w.Url));
spClientContext.ExecuteQuery();
//Lets grab the list that needs to be updated
SP.List OrgList = web.Lists.GetByTitle(ListName);
//Construct a caml query Where the groupID of the SQL Server record is the same
//as the list GroupID
var caml = new Caml<DetailParts>().Where(o => o.GroupID == updateRecord.GroupID);
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml = caml.ToString();
//Load the CAML query
ListItemCollection Rows = OrgList.GetItems(camlQuery);
spClientContext.Load(Rows);
spClientContext.ExecuteQuery();
//The CAML Query should only return one row because GroupID should be UNQIUE
//however due to how sharepoint returns list data we are forcing the first value
//here
ListItem RowToUpdate = Rows[0];
//Get a list of sharepoint columns that match the local detail parts
var ColumnsToUpdate = GetSharePointColumns(typeof(DetailParts));
RowToUpDate["SomeColumn"] = "YOUR NEW VALUE";
RowToUpdate.Update();
//Commit the changes
spClientContext.ExecuteQuery();
}
}
}
catch (Exception ex)
{
//Log any exception and then throw to the caller
logger.Error("Sharepoint exception", ex);
}
That last section of code should be in a function or method of some sort I just pull out the relevant parts. As I Stated this is the only way I found that works and if someone has a better way please share it as I am not a SharePoint expert.

Not able to hide set area using C# Code

We are not able to hide the SET area that is displayed in top navigation bar, I am using the below code snippet to achieve the same. But the subsite is not getting hidden even when the code is not throwing any error. Bit clueless as after unsafe update the code is functioning as expected.
Code Snippet:
using (SPSite siteCollection = new SPSite("http://****:****/VijaiTest/"))
{
using (SPWeb web = siteCollection.RootWeb)
{
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
// Global Navigation
//Show Subsites
publishingWeb.Navigation.GlobalIncludeSubSites = false;
//Show Pages
publishingWeb.Navigation.GlobalIncludePages = false;
// Maximum number of dynamic items to show within this level of navigation:
publishingWeb.Navigation.GlobalDynamicChildLimit = 60;
publishingWeb.IncludeInCurrentNavigation = false;
web.AllowUnsafeUpdates = true;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//Update the changes
publishingWeb.Update();
});
}
}
I see a few potential problems with your code...
1. Don't wrap SPWeb web = sitecollection.RootWeb in a Using statement
While normally it's good practice to wrap SPSite and SPWeb objects in Using statements to ensure that they're disposed of properly, the SPSite.RootWeb property is an exception to this rule. The root web is disposed automatically along with the SPSite object, when it is disposed. Since you have SPSite siteCollection = new SPSite(... wrapped in a Using statement, you don't need to worry about disposal of the RootWeb.
Trying to dispose of the root web twice will add errors to your logs and can cause problems when accessing that web object programmatically.
2. Instantiate your SPSite and SPWeb objects inside your SPSecurity.RunWithElevatedPrivileges delegate
For SPSecurity.RunWithElevatedPrivileges to be effective, you must retrieve or create your SPSite and SPWeb objects within the delegate function.
Your code obtains the SPSite and SPWeb objects prior to running RunWithElevatedPrivileges, so any operations on those objects will run under the context of the current user instead of running with elevated privileges.
3. Check to be sure the SPWeb object is a valid PublishingWeb before executing GetPublishingWeb(web)
From Microsoft:
Before you use this method, check the IsPublishingWeb method to confirm that publishing behavior is supported on this instance of the SPWeb class. If publishing is not supported on the SPWeb, then the methods and properties of the PublishingWeb wrapper may behave unexpectedly.
After those changes, your code would look like this:
SPSecurity.RunWithElevatedPrivileges(delegate() {
using(SPSite siteCollection = new SPSite("http://****:****/VijaiTest/")) {
SPWeb web = siteCollection.RootWeb;
if(PublishingWeb.IsPublishingWeb(web)){
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
// Don't show Subsites
publishingWeb.Navigation.GlobalIncludeSubSites = false;
// Don't show Pages
publishingWeb.Navigation.GlobalIncludePages = false;
// Maximum number of dynamic items to show within this level of navigation:
publishingWeb.Navigation.GlobalDynamicChildLimit = 60;
publishingWeb.IncludeInCurrentNavigation = false;
web.AllowUnsafeUpdates = true;
//Update the changes
publishingWeb.Update();
}else{
throw new Exception("Web is not a publishing web");
}
}
});

Any other option besides using a this object

I'm create a timer job in sharepoint and have made it quite far. I am running into the issue of having a "this" object in a static method. Here is my code. If anyone has any suggestions, that would be great.
public static SPListItemCollection GetRecordwithMissingData (string DocType, string DocName)
{
//Access associate ID and Doc Name
//SPWeb web = properties.Feature.Parent as SPWeb;
SPWebApplication webapp = this.Parent as SPWebApplication;
SPSite hrdocsSite = webapp.Sites["sites/HRDOCS/HRDocuments"];
SPWeb rootweb = hrdocsSite.RootWeb;
SPList AssociateDocumentsList = rootweb.Lists["Associate Documents"];
SPListItemCollection AssociateDocuments = AssociateDocumentsList.GetItems("ID", "PrimaryName", "DocName", "Document Type");
// stores Associate Documents ^
You cannot have "this" in a static method. There is no instance of what "this" is because it refers to the current instance. One way to fix the problem is to pass an extra parameter to pass an instance of the object you are trying to access the property from. The other option is to have a static instance of whatever type "this" is in the class so the method can access it.

Adding to Sharepoint List as Anonymous user

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.

Sharepoint access to list ignore user permission

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.

Categories