Download sharepoint webpart programmatically - sharepoint

We are migrating webparts programmatically.
We used this code in the past but it is not working with modern authentication.
Can you share piece of code for doing this when legacyauth is turned off?
private string DownloadFile(string url)
{
SecureString theSecureString = new NetworkCredential("", _password).SecurePassword;
SharePointOnlineCredentials onlineCredentials = new
SharePointOnlineCredentials(_username, theSecureString);
_authCookieValue = onlineCredentials.GetAuthenticationCookie(new Uri(fileUrl));
using (CookieAwareWebClient client = new CookieAwareWebClient())
{
client.CookieContainer = new CookieContainer();
client.CookieContainer.Add(new Cookie("SPOIDCRL",
_authCookieValue.TrimStart("SPOIDCRL=".ToCharArray()), String.Empty, authority));
string localPath = Path.GetTempPath();
string temporaryGuid = Guid.NewGuid().ToString();
string path = System.IO.Path.Combine(localPath, temporaryGuid);
client.DownloadFile(fileUrl, path);
document = System.IO.File.ReadAllText(path);
System.IO.File.Delete(path);
}
}
etc...
}
We were calling it this way:
string itemWebPartDefUrl = string.Format(
"{0}{1}/_vti_bin/exportwp.aspx?pageurl={2}&guidstring={3}",
_rootPrefixURL,
webServerRelativeUrl,
pageURL,
wpDef.Id.ToString().ToLower()
);
Uri targetSite = new Uri(_context.Web.Url);
string xmlDef = DownloadFile(itemWebPartDefUrl, targetSite.Authority);

Related

Azure Blob Storage - Error trying to delete blob with API REST with C#

I'm working with Azure Blob Storage and C#. I need to delete a blob using the API REST, but I get the 403 Forbidden error. I'm using the same function to generate the authentication header for create a new blob, but it works for put but doesn't it for delete. This is my code:
public bool DeleteBlob(string containerName, string fileName)
{
string blobName = fileName;
string method = "DELETE";
string requestUri = $"https://{_accountName}.blob.core.windows.net/{containerName}/{blobName}";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
string now = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
request.Method = method;
request.Headers.Add("x-ms-version", "2020-10-02");
request.Headers.Add("x-ms-date", now);
request.Headers.Add("x-ms-delete-snapshots", "include");
request.Headers.Add("Authorization", AuthorizationHeader("DELETE", request, containerName, blobName));
bool result = false;
using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
{
if (resp.StatusCode != HttpStatusCode.Accepted && resp.StatusCode != HttpStatusCode.OK)
{
throw new Exception(resp.StatusDescription);
}
result = true;
}
return result;
}
private string AuthorizationHeader(string method, HttpWebRequest request, string containerName, string blobName)
{
string urlResource = $"/{_accountName}/{containerName}/{blobName}";
string stringToSign = $"{method}\n\n\n{request.ContentLength}\n\n{request.ContentType}\n\n\n\n\n\n\n{GetCanonicalizedHeaders(request)}{GetCanonicalizedResource(request.RequestUri, _accountName)}";
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(_accountKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
return string.Format("{0} {1}:{2}", "SharedKey", _accountName, signature);
}
private string GetAuthorizationHeader(string method, HttpWebRequest request, string now, string containerName, string blobName)
{
string urlResource = $"/{_accountName}/{containerName}/{blobName}";
var canonicalizedStringToBuild = string.Format("{0}\n{1}", now, $"/{_accountName}/" + urlResource);
string signature;
using (var hmac = new HMACSHA256(Convert.FromBase64String(_accountKey)))
{
byte[] dataToHmac = Encoding.UTF8.GetBytes(canonicalizedStringToBuild);
signature = Convert.ToBase64String(hmac.ComputeHash(dataToHmac));
}
return string.Format($"{_accountName}:" + signature);
}
private string GetCanonicalizedHeaders(HttpWebRequest request)
{
ArrayList headerNameList = new ArrayList();
StringBuilder sb = new StringBuilder();
foreach (string headerName in request.Headers.Keys)
{
if (headerName.ToLowerInvariant().StartsWith("x-ms-", StringComparison.Ordinal))
{
headerNameList.Add(headerName.ToLowerInvariant());
}
}
headerNameList.Sort();
foreach (string headerName in headerNameList)
{
StringBuilder builder = new StringBuilder(headerName);
string separator = ":";
foreach (string headerValue in GetHeaderValues(request.Headers, headerName))
{
string trimmedValue = headerValue.Replace("\r\n", String.Empty);
builder.Append(separator);
builder.Append(trimmedValue);
separator = ",";
}
sb.Append(builder.ToString());
sb.Append("\n");
}
return sb.ToString();
}
private string GetCanonicalizedResource(Uri address, string accountName)
{
StringBuilder str = new StringBuilder();
StringBuilder builder = new StringBuilder("/");
builder.Append(accountName);
builder.Append(address.AbsolutePath);
str.Append(builder.ToString());
NameValueCollection values2 = new NameValueCollection();
if (address.Query.Length > 0)
{
string query = address.Query.Remove(0, 1);
var queryParts = query.Split('&');
foreach (var queryPart in queryParts)
{
var parts = queryPart.Split('=');
values2.Add(parts[0], parts[1]);
}
ArrayList list2 = new ArrayList(values2.AllKeys);
list2.Sort();
foreach (string str3 in list2)
{
StringBuilder builder3 = new StringBuilder(string.Empty);
builder3.Append(str3);
builder3.Append(":");
builder3.Append(values2[str3]);
str.Append("\n");
str.Append(builder3.ToString());
}
}
return str.ToString();
}
Could anyone tell me what I'm doing wrong? As I commented for create a new blob working fine, but not for deletion. I don't know if the authentication header is different for delete (I know the method name is different) I have not found much information about that.
Thannks.
The reason your delete operation is failing with 403 error is because in your stringToSign you're assigning content length as 0 whereas it should be an empty string.
Please change your AuthorizationHeader method code to the code mentioned below and your delete blob operation should work just fine:
private string AuthorizationHeader(string method, HttpWebRequest request, string containerName, string blobName)
{
string urlResource = $"/{_accountName}/{containerName}/{blobName}";
var contentLength = request.ContentLength == 0 ? "" : request.ContentLength.ToString();
string stringToSign = $"{method}\n\n\n{contentLength}\n\n{request.ContentType}\n\n\n\n\n\n\n{GetCanonicalizedHeaders(request)}{GetCanonicalizedResource(request.RequestUri, _accountName)}";
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(_accountKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
return string.Format("{0} {1}:{2}", "SharedKey", _accountName, signature);
}
What I have done above is set the content length value to an empty string if the content length is 0.
From this link (emphasis mine):
In the current version, the Content-Length field must be an empty
string if the content length of the request is zero. In version
2014-02-14 and earlier, the content length was included even if zero.

Create Folder and Update Title and Custom Field in Sharepoint Online

I try to create folder in sharepoint online, based on some of tutorial. the problem comes since creating folder is not given "Title" column value.
I want to create folder and also update column "Title".
here is the code for create folder
public string CreateDocumentLibrary(string siteUrl, string relativePath)
{
//bool responseResult = false;
string resultUpdate = string.Empty;
string responseResult = string.Empty;
if (siteUrl != _siteUrl)
{
_siteUrl = siteUrl;
Uri spSite = new Uri(siteUrl);
_spo = SpoAuthUtility.Create(spSite, _username, WebUtility.HtmlEncode(_password), false);
}
string odataQuery = "_api/web/folders";
byte[] content = ASCIIEncoding.ASCII.GetBytes(#"{ '__metadata': { 'type': 'SP.Folder' }, 'ServerRelativeUrl': '" + relativePath + "'}");
string digest = _spo.GetRequestDigest();
Uri url = new Uri(String.Format("{0}/{1}", _spo.SiteUrl, odataQuery));
// Set X-RequestDigest
var webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
webRequest.Headers.Add("X-RequestDigest", digest);
// Send a json odata request to SPO rest services to fetch all list items for the list.
byte[] result = HttpHelper.SendODataJsonRequest(
url,
"POST", // reading data from SP through the rest api usually uses the GET verb
content,
webRequest,
_spo // pass in the helper object that allows us to make authenticated calls to SPO rest services
);
string response = Encoding.UTF8.GetString(result, 0, result.Length);
if (response != null)
{
//responseResult = true;
responseResult = response;
}
return responseResult;
}
I already tried to use CAML, but, the problem is, the list of sharepoint is big, so got the error prohibited access related to limit tresshold.
Please help.
Refer below code to update folder name.
function renameFolder(webUrl,listTitle,itemId,name)
{
var itemUrl = webUrl + "/_api/Web/Lists/GetByTitle('" + listTitle + "')/Items(" + itemId + ")";
var itemPayload = {};
itemPayload['__metadata'] = {'type': getItemTypeForListName(listTitle)};
itemPayload['Title'] = name;
itemPayload['FileLeafRef'] = name;
var additionalHeaders = {};
additionalHeaders["X-HTTP-Method"] = "MERGE";
additionalHeaders["If-Match"] = "*";
return executeJson(itemUrl,"POST",additionalHeaders,itemPayload);
}
function getItemTypeForListName(name) {
return"SP.Data." + name.charAt(0).toUpperCase() + name.slice(1) + "ListItem";
}

How can I create new site (not subsite ) in sharepoint online using CSOM

I want to create new site at root level (not subsite in existing site). I am using CSOM for creating site. In current scenario I need to provide the Site URL to client context for authentication and perform operations. Here is a pseudo code.
string url = "https://mysharepoint.com/sites/testsite";
SecureString f_SecurePass = new SecureString();
foreach (char ch in pass)
f_SecurePass.AppendChar(ch);
clientcontext = new ClientContext(url);
var credentials = new SharePointOnlineCredentials(userid, f_SecurePass);
clientcontext.Credentials = credentials;
Web web = clientcontext.Web;
clientcontext.Load(web, website => website.Lists);
clientcontext.ExecuteQuery();
WebCreationInformation wci = new WebCreationInformation();
wci.Url = "/TestAPISite2";
wci.Title = "TestAPISite2";
wci.Language = 1033;
var newsite = clientcontext.Site.RootWeb.Webs.Add(wci);
clientcontext.ExecuteQuery();
Please suggest the solution.
Regarding the requirement:
I want to create new site at root level (not subsite in existing
site).
in SharePoint terminology it is called a site collection:
site collection / top level site / parent site - a site collection
is a web site that can contain sub-sites (aka webs)
In SharePoint CSOM API Tenant class is intended for that purpose, in particular Tenant.CreateSite method.
Here is an example:
const string username = "username#contoso.onmicrosoft.com";
const string password = "password";
const string tenantAdminUrl = "https://contoso-admin.sharepoint.com/";
using (var ctx = GetContext(tenantAdminUrl,userName,password))
{
CreateSite(ctx, "https://contoso.sharepoint.com/sites/marketing","Marketing");
}
where
internal static void CreateSite(ClientContext context, String url, String owner, String title =null, String template = null, uint? localeId = null, int? compatibilityLevel = null, long? storageQuota = null, double? resourceQuota = null, int? timeZoneId = null)
{
var tenant = new Tenant(context);
if (url == null)
throw new ArgumentException("Site Url must be specified");
if (string.IsNullOrEmpty(owner))
throw new ArgumentException("Site Owner must be specified");
var siteCreationProperties = new SiteCreationProperties {Url = url, Owner = owner};
if (!string.IsNullOrEmpty(template))
siteCreationProperties.Template = template;
if (!string.IsNullOrEmpty(title))
siteCreationProperties.Title = title;
if (localeId.HasValue)
siteCreationProperties.Lcid = localeId.Value;
if (compatibilityLevel.HasValue)
siteCreationProperties.CompatibilityLevel = compatibilityLevel.Value;
if (storageQuota.HasValue)
siteCreationProperties.StorageMaximumLevel = storageQuota.Value;
if (resourceQuota.HasValue)
siteCreationProperties.UserCodeMaximumLevel = resourceQuota.Value;
if (timeZoneId.HasValue)
siteCreationProperties.TimeZoneId = timeZoneId.Value;
var siteOp = tenant.CreateSite(siteCreationProperties);
context.Load(siteOp);
context.ExecuteQuery();
}
and
public static ClientContext GetContext(string url, string userName, string password)
{
var securePassword = new SecureString();
foreach (var ch in password) securePassword.AppendChar(ch);
return new ClientContext(url) {Credentials = new SharePointOnlineCredentials(userName, securePassword)};
}

Google Docs API - Impersonate User File Download

Using the Google Docs Java API with a Google Apps account, is it possible to impersonate a user and download a file?
When I run the program below, it is clearly logging on to the domain and impersonating the user because it retrieves the details of one of the files and prints out the file title. However, when it tries to download the file, a ServiceForbiddenException is thrown.
If it is not possible with the Java API, does anyone know if it is possible for my program to write an HTTP request to download the file using the Protocol API?
public class AuthExample {
private static DocsService docService = new DocsService("Auth Example");
public static void main(String[] args)
throws Exception
{
String adminUser = args[0];
String adminPassword = args[1];
String authToken = args[2];
String impersonatedUser = args[3];
loginToDomain(adminUser, adminPassword, authToken);
URL url = new URL( "https://docs.google.com/feeds/" + impersonatedUser + "/private/full" );
DocumentListFeed feed = docService.getFeed(url, DocumentListFeed.class);
DocumentListEntry entry = feed.getEntries().get(0);
String title = entry.getTitle().getPlainText();
System.out.println( title );
String type = entry.getType();
if ( type.equals("document") )
{
String encodedAdminUser = URLEncoder.encode(adminUser);
String resourceId = entry.getResourceId();
String resourceIdNoPrefix = resourceId.substring( resourceId.indexOf(':')+1 );
String downloadUrl =
"https://docs.google.com/feeds/download/documents/Export" +
"?xoauth_requestor=" + encodedAdminUser +
"&docId=" + resourceIdNoPrefix +
"&exportFormat=doc";
downloadFile( downloadUrl, title + ".doc" );
}
}
private static void loginToDomain(String adminUser, String adminPassword, String authToken)
throws OAuthException, AuthenticationException
{
String domain = adminUser.substring( adminUser.indexOf('#')+1 );
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(domain);
oauthParameters.setOAuthConsumerSecret(authToken);
oauthParameters.setOAuthType(OAuthType.TWO_LEGGED_OAUTH);
oauthParameters.setScope("https://docs.google.com/feeds/ http://spreadsheets.google.com/feeds/ http://docs.googleusercontent.com/");
docService.useSsl();
docService.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());
docService.setUserCredentials(adminUser, adminPassword);
}
// Method pasted directly from Google documentation
public static void downloadFile(String exportUrl, String filepath)
throws IOException, MalformedURLException, ServiceException
{
System.out.println("Exporting document from: " + exportUrl);
MediaContent mc = new MediaContent();
mc.setUri(exportUrl);
MediaSource ms = docService.getMedia(mc);
InputStream inStream = null;
FileOutputStream outStream = null;
try {
inStream = ms.getInputStream();
outStream = new FileOutputStream(filepath);
int c;
while ((c = inStream.read()) != -1) {
outStream.write(c);
}
} finally {
if (inStream != null) {
inStream.close();
}
if (outStream != null) {
outStream.flush();
outStream.close();
}
}
}
}
Impersonation will work as intended if you use Oauth2 with ServiceAccounts

SharePoint 2010: Count ListItem Attachments using Client Object Model

Does anyone know how to read the number of attachments, and the names etc for a ListItem using the Client .Net Object model in SharePoint?
Thanks
// For getting the list item field information
public void LoadPropertyInfo()
{
using (context = new ClientContext(siteCollectionUrl))
{
spWeb = context.Web;
propertiesList = spWeb.Lists.GetByTitle(listName);
FieldCollection fields = propertiesList.Fields;
context.Load(fields);
SP.CamlQuery query = new SP.CamlQuery();
query.ViewXml = string.Format("<View><Query><Where><Eq><FieldRef Name=\"{0}\" /><Value Type=\"Text\">{1}</Value></Eq></Where></Query></View>", propertyID, PropertyIDValue);
listItems = propertiesList.GetItems(query);
context.Load(listItems);
context.ExecuteQueryAsync(GetRequestSucceeded, RequestFailed);
}
}
// Pass the item id here for getting the attachments
private void GetAttchmentCollection(string id)
{
string RedirectHost = string.Empty;
string Host = string.Empty;
context = SP.ClientContext.Current;
RedirectHost = serviceUrl + "_vti_bin/Lists.asmx";
BasicHttpBinding binding = new BasicHttpBinding();
if (System.Windows.Browser.HtmlPage.Document.DocumentUri.Scheme.StartsWith("https"))
{
binding.Security.Mode = BasicHttpSecurityMode.Transport;
}
binding.MaxReceivedMessageSize = int.MaxValue;
EndpointAddress endpoint = new EndpointAddress(RedirectHost);
ServiceReference1.ListsSoapClient oClient = new ServiceReference1.ListsSoapClient(binding, endpoint);
oClient.GetAttachmentCollectionCompleted += new EventHandler<ServiceReference1.GetAttachmentCollectionCompletedEventArgs>(oClient_GetAttachmentCollectionCompleted);
oClient.GetAttachmentCollectionAsync(listName, id);
}
Your can try this link too.
http://helpmetocode.blogspot.com/2011/11/managed-client-object-models-in.html

Resources