我看到这已经被问过很多次了,但是我遇到的所有示例都不起作用或在 JavaScript 中,我需要 C# 的帮助。
我有一个带有服务器站点集合的场,我成功创建了一个提供程序托管的插件/应用程序,当它尝试访问启动它的 Web 上的列表时,一切都很好!我需要尝试访问同一农场和同一域中其他网站上的列表是否有人有可以执行此操作的 C# 代码示例
我看到这已经被问过很多次了,但是我遇到的所有示例都不起作用或在 JavaScript 中,我需要 C# 的帮助。
我有一个带有服务器站点集合的场,我成功创建了一个提供程序托管的插件/应用程序,当它尝试访问启动它的 Web 上的列表时,一切都很好!我需要尝试访问同一农场和同一域中其他网站上的列表是否有人有可以执行此操作的 C# 代码示例
您可以像这样创建存储库方法:
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;
}
}
}
此方法使用托管 csom。
如果您遇到 ADFS 问题,请尝试在此行之后添加
context.Credentials = CredentialCache.DefaultCredentials;
这个
context.ExecutingWebRequest += new EventHandler<WebRequestEventArgs>(MixedAuthRequestMethod);
和这个功能
void MixedAuthRequestMethod(object sender, WebRequestEventArgs e) { e.WebRequestExecutor.RequestHeaders.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f"); }
这是一个基本的参考: https ://msdn.microsoft.com/en-us/library/office/fp179912.aspx
您还应该查看 Sharepoint 应用程序模型和 Rest OData API。
我想通了,所以我发布它以防其他人需要它,也请理解我对 SharePoint 完全是菜鸟,这可能不是最好的方式,甚至不是 SharePoint 接受的做事方式。
首先,您需要授予您应用租户权限(完全控制或管理)!- 很重要
其次,我创建了这个函数,它将 SharePoint 上下文创建到一个站点,而不是运行应用程序的站点
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();
}
正如你所看到的,我不得不修改 Querystring 并获取一些值,所以这里是执行该操作的 Utility 类:
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);
}
}
最后,SharePoint 访问代码看起来与网络上的许多相同 SharePoint 代码很相似,我必须从中删除一些可以识别项目或项目对象的内容,但应该很容易挑选出您需要的内容从内部
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);
}
最后一段代码应该在某种函数或方法中,我只是拉出相关部分。正如我所说,这是我发现可行的唯一方法,如果有人有更好的方法,请分享它,因为我不是 SharePoint 专家。