从完整的 url 中获取列表名称

Get List Name from full url

我收到了数百个不同的随机 URL,所有文档都在库中,没有来自不同场、不同网站集和网站的任何其他参数,目标是从 SharePoint 下载二进制数组形式的文件。

例如传入 url = http://a.b.c.d.e/f.g/h.i/j/k/l/m.docx .

那么如何从中获取 (a) 正确的网站集根 url (b) 网站根 url (c) 库根 url?我现在想到的唯一方法是慢慢剥离 url 的每个部分,直到例如.Rootfolder 不再给出异常......或者通过 url 的第一部分缓慢添加位的其他方式,直到 rootfolder 不再给出异常然后查询子网站等..

我已经做了一个工作方法,但它看起来很复杂,所以欢迎任何改进建议,只是 "download file if one of the specific columns has value "yes":

public void getDocument(Document doc)
    {
        // get the filename
        Uri uri = new Uri(doc.uri);
        doc.filename = "";
        doc.filename = System.IO.Path.GetFileName(uri.LocalPath);
        //string fullPathWithoutFileName = docUri.Replace(filename, "");
        // would also include ?a&b so:           
        string[] splitDocUri = doc.uri.Split('/');
        string fullPathWithoutFileName = "";
        for (int i = 0; i < splitDocUri.Length -1; i++)
        {
            fullPathWithoutFileName += (splitDocUri[i] + '/');
        }

        // get via "_api/contextinfo" the context info
        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(fullPathWithoutFileName + "_api/contextinfo");
        req.Method = "POST";
        req.Accept = "application/json; odata=verbose";
        req.Credentials = new NetworkCredential(doc.username, doc.password, doc.domain);
        req.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED","f");
        req.ContentLength = 0;
        BypassCertificateError();
        HttpWebResponse rp = (HttpWebResponse)req.GetResponse();
        Stream postStream = rp.GetResponseStream();
        StreamReader postReader = new StreamReader(postStream);
        string results = postReader.ReadToEnd();
        // Now parse out some values needs system.web.extensions
        JavaScriptSerializer jss = new JavaScriptSerializer();
        var d = jss.Deserialize<dynamic>(results);
        string formDigestValue = d["d"]["GetContextWebInformation"]["FormDigestValue"];
        // the full url to the website e.g. "http://server:7777/level1/level 2"     
        string webFullUrl = d["d"]["GetContextWebInformation"]["WebFullUrl"];
        // the full url to the site collection e.g.       "http://server:7777"
        string siteFullUrl = d["d"]["GetContextWebInformation"]["SiteFullUrl"];

        // now we can create a context
        ClientContext ctx = new ClientContext(webFullUrl);
        ctx.ExecutingWebRequest +=
          new EventHandler<WebRequestEventArgs>(ctx_MixedAuthRequest);
        BypassCertificateError();
        ctx.AuthenticationMode = ClientAuthenticationMode.Default;
        ctx.Credentials = new NetworkCredential(doc.username, doc.password, doc.domain);

        // Get the List
        Microsoft.SharePoint.Client.File file = ctx.Web.GetFileByServerRelativeUrl(uri.AbsolutePath);
        List list = file.ListItemAllFields.ParentList;
        ctx.Load(list);
        ctx.ExecuteQuery();

        // execute a CAML query against it
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml =
            "<View><Query><Where><Eq><FieldRef Name='FileLeafRef'/>" +
            "<Value Type='Text'>" + doc.filename + "</Value></Eq></Where>" +
            "<RowLimit>1</RowLimit></Query></View>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        ctx.Load(listItems);
        try {
            ctx.ExecuteQuery();
        }
        catch
        {
            // e.g. : no access or the listname as incorrectly deduced
            throw;
        }

        // and now retrieve the items needed
        if (listItems.Count == 1)
        {
            ListItem item = listItems[0];
            // some more checking from testColumn to decide if to download yes/no
            string testColumn;
            if (item.IsPropertyAvailable("testColumn")) {
                testColumn = (string)item["testColumn"];
            }

            FileInformation fileInformation =
                Microsoft.SharePoint.Client.File.OpenBinaryDirect(ctx,
                    (string)item["FileRef"]);
            doc.bytes = ReadFully(fileInformation.Stream);

        }
        else
        {
            doc.errormessage = "Error: No document found";
        }

    }

重点是ClientContext constructor只接受web/site的url。 但是如果 url 将指定为以下格式:

http://site/web/documents/file.docx

那么就会出现异常System.Net.WebException

以下示例演示如何从请求 Url 解析 ClientContext

public static class ClientContextUtilities
{
    /// <summary>
    /// Resolve client context  
    /// </summary>
    /// <param name="requestUri"></param>
    /// <param name="context"></param>
    /// <param name="credentials"></param>
    /// <returns></returns>
    public static bool TryResolveClientContext(Uri requestUri, out ClientContext context, ICredentials credentials)
    {
        context = null;
        var baseUrl = requestUri.GetLeftPart(UriPartial.Authority);
        for (int i = requestUri.Segments.Length; i >= 0; i--)
        {
            var path = string.Join(string.Empty, requestUri.Segments.Take(i));
            string url = string.Format("{0}{1}", baseUrl, path);
            try
            {
                context = new ClientContext(url);
                if (credentials != null)
                    context.Credentials = credentials;
                context.ExecuteQuery();
                return true;
            }
            catch (Exception ex) {}
        }
        return false;
    }

}

用法

ClientContext context;
if (ClientContextUtilities.TryResolveClientContext(requestUri, out context, null))
{
     using (context)
     {
         var baseUrl = requestUri.GetLeftPart(UriPartial.Authority);
         var fileServerRelativeUrl = requestUri.ToString().Replace(baseUrl, string.Empty);                  
         var file = context.Web.GetFileByServerRelativeUrl(fileServerRelativeUrl);
         context.Load(file); 
         context.Load(context.Web);
         context.Load(context.Site);
         context.ExecuteQuery();
     }
}

由于您的目标是下载文件,因此有一种无需解析 url 部分即可完成的非常简单的方法。

例如,使用WebClient.DownloadFile Method

private static void DownloadFile(Uri fileUri, ICredentials credentials, string localFileName)
{
     using(var client = new WebClient())
     {
        client.Credentials = credentials;
        client.DownloadFile(fileUri, localFileName);
     }  
}