Information cannot be obtained from shared link URLs created by others - c#

I want to see the shared link information from the OneDrive shared link URL.
If you use the shared link URL created by yourself (test001) as a parameter, you will succeed in getting the information.
string sharingUrl = "https://test001-my.sharepoint.com/:t:/g/personal/test001_...";
string base64Value = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(sharingUrl));
string encodedUrl = "u!" + base64Value.TrimEnd('=').Replace('/', '_').Replace('+', '-');
var item = await graphClient.Shares[encodedUrl].Request().GetAsync();
When trying to get information from a shared link URL created by another user (test002)
string sharingUrl = "https://test001-my.sharepoint.com/:t:/g/personal/test002_...";
string base64Value = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(sharingUrl));
string encodedUrl = "u!" + base64Value.TrimEnd('=').Replace('/', '_').Replace('+', '-');
var item = await graphClient.Shares[encodedUrl].Request().GetAsync();
System.NullReferenceException occurs in the above process.
What am I doing wrong?

Related

SharePointContextFilter attribute fails to rebuild SharePoint context

I have developed a SharePoint add-in (SharePoint Online) and it is hosted in Azure. The add-in is an ASP.NET MVC application.
Here's the situation:
/Home/Index: The user starts on the landing page of the application and goes to the section Actions.
Actions/Index: On this page, the user has to select a few parameters and select an action to edit
Actions/Edit/123: The edit page opens, a form is shown with all controls filled in with the information about the action.
POST: After changing some fields, or none, the user clicks the Save button.
I didn't show it in the list but all the URLs have the SPHostUrl, SPAppWebUrl, SPLanguage, SPClientTag & SPProductNumber parameters.
This all works fine, except when the user doesn't interact with the application/page for a number of minutes and then presses the Save button. When the button is pressed, the application fails to pass the SharePointContextFilter attribute. The SharePointContext doesn't "exist" anymore. Following line returns null:
SharePointContext spContext = LoadSharePointContext(httpContext);
Normally, if it doesn't exist or isn't valid, the code will try and create it based based on the request. In the CreateSharePointContext method, the contextTokenString is always null:
string contextTokenString = TokenHelper.GetContextTokenFromRequest(httpRequest);
This is the code of the method:
public static string GetContextTokenFromRequest(HttpRequestBase request)
{
string[] paramNames = { "AppContext", "AppContextToken", "AccessToken", "SPAppToken" };
foreach (string paramName in paramNames)
{
if (!string.IsNullOrEmpty(request.Form[paramName]))
{
return request.Form[paramName];
}
if (!string.IsNullOrEmpty(request.QueryString[paramName]))
{
return request.QueryString[paramName];
}
}
return null;
}
So, if this fails, the creation and saving of the context fails and the app returns the default error page.
This is the jQuery code that makes the call to the controller:
var request = $.ajax({
url: '#Url.Action("Edit", "Actions")' + window.buildSpAppParameters(),
data: $("#updateForm").serialize(),
cache: false,
type: "POST"
});
Here's the code of the buildSpAppParameters function:
function buildSpAppParameters() {
var spHostUrl = getQueryStringParameter("SPHostUrl");
var appWebUrl = getQueryStringParameter("SPAppWebUrl");
var spLanguage = getQueryStringParameter("SPLanguage");
var spClientTag = getQueryStringParameter("SPClientTag");
var spProductNr = getQueryStringParameter("SPProductNumber");
return "?SPHostUrl=" + spHostUrl +
"&SPAppWebUrl=" + appWebUrl +
"&SPLanguage=" + spLanguage +
"&SPClientTag=" + spClientTag +
"&SPProductNumber=" + spProductNr;
}
Why does this initially work, but if the user waits a period of time, the code is unable to get/create the context again? Is there something I am missing and how can solve this?
Note: I am aware of following question: Sharepoint 2013 MVC 5 provider-hosted app. Fails to authenticate on HttpPost using [SharePointContextFilter] and while there is useful information to read, it didn't help me further.
This all works fine, except when the user doesn't interact with the application/page for a number of minutes
The session is expired and the SharePointContext is lost. So we need to regenerate the context.
According to the GetContextTokenFromRequest method, the context token should be passed in query string or forms. But from the buildSpAppParameters method, we can't found the context token is passed from the query string. The query string parameter should be named AppContext or AppContextToken or AccessToken or SPAppToken.
To solve this issue, you could check whether your current URL in your brower contains a query parameter named AppContext or AppContextToken or AccessToken or SPAppToken. If yes, you could read the value this parameter out from URL and pass it server in your buildSpAppParameters method. For example, if your URL contains a query parameter named AppContextToken, you could modify your code as following.
function buildSpAppParameters() {
var spHostUrl = getQueryStringParameter("SPHostUrl");
var appWebUrl = getQueryStringParameter("SPAppWebUrl");
var spLanguage = getQueryStringParameter("SPLanguage");
var spClientTag = getQueryStringParameter("SPClientTag");
var spProductNr = getQueryStringParameter("SPProductNumber");
var appContextToken = getQueryStringParameter("AppContextToken");
return "?SPHostUrl=" + spHostUrl +
"&SPAppWebUrl=" + appWebUrl +
"&SPLanguage=" + spLanguage +
"&SPClientTag=" + spClientTag +
"&SPProductNumber=" + spProductNr +
"&AppContextToken=" + appContextToken;
}
If your URL doesn't contain such query parameters, you need to modify your code to store the context token in cookie when the context token was got at the first time.
string contextTokenString = TokenHelper.GetContextTokenFromRequest(httpRequest);
if (!string.IsNullOrEmpty(contextTokenString))
{
HttpCookie cookie = new HttpCookie("AppContextToken", contextTokenString);
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
}
After that, the context token can be got from the cookie if the token haven't been passed through query string.
public static string GetContextTokenFromRequest(HttpRequestBase request)
{
string[] paramNames = { "AppContext", "AppContextToken", "AccessToken", "SPAppToken" };
foreach (string paramName in paramNames)
{
if (!string.IsNullOrEmpty(request.Form[paramName]))
{
return request.Form[paramName];
}
if (!string.IsNullOrEmpty(request.QueryString[paramName]))
{
return request.QueryString[paramName];
}
}
if (request.Cookies["AppContextToken"] != null)
{
return request.Cookies["AppContextToken"].Value;
}
return null;
}

How do I access SoftLayer object storage from a C# application for Android, developed in Visual Studio.

How do I access SoftLayer object storage from a C# application for Android, developed in Visual Studio. I am trying to add a Web Reference in VS so that I can use the storage API services. I have read http://sldn.softlayer.com/reference/objectstorageapi http://docs.openstack.org/developer/swift/api/object_api_v1_overview.html but still can't find how to do this.
Thanks, greatly appreciated - the next part of the task was to upload a file on the Android device to Object Storage. The code is a bit(!) messy and lacks error checking but hopefully will point anyone else trying to do this in the right direction.
var path = Android.OS.Environment.ExternalStorageDirectory ;
var filename = path + Java.IO.File.Separator + string.Format("{0}", prefix) + "mydata.txt";
string username = "SLOS1234567-1:SL1234567";
string apiKey = "1234567891234567891234567891234567891234567891234567891234567891";
string tokenval, URLval, URLcomp;
//Create a web request for authentication.
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create("https://syd01.objectstorage.softlayer.net/auth/v1.0");
//Get the headers associated with the request.
WebHeaderCollection myWebHeaderCollection = myHttpWebRequest.Headers;
//Add the X-Auth-User header (for OS user) in the request.
myWebHeaderCollection.Add("X-Auth-User", username);
//Add the X-Auth-Key header (for the API key) in the request.
myWebHeaderCollection.Add("X-Auth-Key",apiKey);
//Get the associated response - the auth token and storage URL.
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
tokenval = myHttpWebResponse.GetResponseHeader("X-Auth-Token");
URLval = myHttpWebResponse.GetResponseHeader("X-Storage-Url");
URLcomp = URLval + "/mycontainer/myDirectory/" + string.Format("{0}", prefix) + "mydata.txt";
//Upload the file
WebClient wc = new WebClient();
wc.Headers.Add("X-Auth-Token",tokenval);
wc.UploadFile(URLcomp, "PUT", filename);
For using C# for SoftLayer, there’s the next link available:
https://sldn.softlayer.com/article/C-Sharp
The next link provides Object Storage information for REST:
http://sldn.softlayer.com/blog/waelriac/managing-softlayer-object-storage-through-rest-apis
The next is an example of how C# can be used to interact with the SoftLayer API. The example follows the previous C# link.
using System;
using Newtonsoft.Json;
namespace GetHubNetworkStorage
{
class Program
{
static void Main(string[] args)
{
string username = "set me";
string apiKey = "set me";
authenticate authenticate = new authenticate();
authenticate.username = username;
authenticate.apiKey = apiKey;
SoftLayer_AccountService accountService = new SoftLayer_AccountService();
accountService.authenticateValue = authenticate;
try
{
// The result is an array of SoftLayer_Network_Storage objects and can be either iterated
// one by one to use the data or being displayed as a JSON value such in this example.
var hubNetworkStorages = accountService.getHubNetworkStorage();
string json = JsonConvert.SerializeObject(hubNetworkStorages, Formatting.Indented);
Console.WriteLine(json);
}
catch (Exception e)
{
Console.WriteLine("Can't retrieve SoftLayer_Network_Storage information: " + e.Message);
}
Console.ReadKey();
}
}
}
The next link also might help you if you decide to manage the object-storage-rest-api through curl but wrapped into C# code:
Making a cURL call in C#

Amazon MWS client library C# AWS Access Key Id error

I am using Amazon C# client library to get product information and keep getting an error " The AWS Access Key Id you provided does not exist in our records." (Yes, I tried the seller forum, but didn't get an answer there). When I use the same Access Key using their scratchpad, I get the correct response. I did see this post (Getting 'The AWS Access Key Id you provided does not exist in our records' error with Amazon MWS) and tried swapping the parameters and that didn't work. Here is my C# code. Any help would be greatly appreciated
string AccessKey = "xxx";
string SecretKey = "xxx";
string AppName = "ProductFunctionsApp";
string AppVersion = "1.0";
string ServiceURL = "https://mws.amazonservices.com/Products/2011-10-01";
string SellerId="xxxx";
string MarketPlaceId = "xxx";//US
//right now MWSAuthToken is only if a developer is using a sellers account
MarketplaceWebServiceProductsConfig config = new MarketplaceWebServiceProductsConfig();
config.ServiceURL = ServiceURL;
config.SignatureMethod = "HmacSHA256";
config.SignatureVersion = "2";
MarketplaceWebServiceProductsClient client = new MarketplaceWebServiceProductsClient(AppName, AccessKey, SecretKey, AppVersion, config);
ASINListType type = new ASINListType();
List<string> ASINList = new List<string>();
ASINList.Add("B001E6C08E");
type.ASIN = ASINList;
;
GetCompetitivePricingForASINRequest request = new GetCompetitivePricingForASINRequest();
request.SellerId = SellerId;
request.ASINList = type;
request.MarketplaceId = MarketPlaceId;
GetCompetitivePricingForASINResponse response = client.GetCompetitivePricingForASIN(request);
Some of their API Clients have the class initialization parameters defined in different orders.
So if you copy and paste the initialization code you'll end up with the application name being sent instead of the access key.
var service = new MarketplaceWebServiceProductsClient(
applicationName, applicationVersion, accessKeyId, secretAccessKey, config);
And it's different here:
var service = new FBAInventoryServiceMWSClient(
accessKeyId, secretAccessKey, applicationName, applicationVersion, config);
Just check each one carefully.

Get anything after first slash in URL

I can get my browser url using : string url = HttpContext.Current.Request.Url.AbsoluteUri;
But say if I have a url as below :
http://www.test.com/MyDirectory/AnotherDir/testpage.aspx
How would I get the "MyDirectory" part of it, is there a utility in .NET to get this or do I need string manipulation ?
If I do string manipulation and say anything after first instance of "/" then wouldnt it return the slash after http:? It would work if my url was www.test.com/MyDirectory/AnotherDir/testpage.aspx
Can someone please help
Instantiate a Uri instance from your url:
Uri myUri = new Uri("http://www.test.com/MyDirectory/AnotherDir/testpage.aspx");
You can then get the path segments into a string array using:
string[] segments = myUri.Segments
Your first "MyDirectory" folder will be at:
string myFolderName = segments[0];
You can get this by PathAndQuery property of Url
var path = HttpContext.Current.Request.Url.PathAndQuery;
it will return /MyDirectory/AnotherDir/testpage.aspx
Uri uriAddr = new Uri("http://www.test.com/MyDirectory/AnotherDir/testpage.aspx");
var firstSegment= uriAddress.Segments.Where(seg => seg != "/").First();

Google Analytics API - Programmatically fetch page views in server side

We have a web application that consists of several pages. We registered our web app domain to Google Analytics and page views tracking works as expected (In the Analytics panel we can see page views for each page). Now we want this page views info to be stored in the back-end inside our DB. So we want to create a back-end process that will run once each day, and fetch the page views from Analytics API.
This is of course need to be done in code. From initial research it seems that in order to access Analytics API an authentication process must take place, meaning a human user must type in an id and password.
The question is, can it be done with code only ?
//-------------- Get Auth Token -------------------
WebClient webClient = new WebClient();
NameValueCollection data = new NameValueCollection();
data.Add("accountType", "GOOGLE");
data.Add("Email", "xxxx#gmail.com");
data.Add("Passwd", "xxxx");//Passwd, not a misspell.
data.Add("service", "analytics");
data.Add("source", "xxxx-xxxx-xx");//Could be anything.
byte[] bytes = webClient.UploadValues("https://www.google.com/accounts/ClientLogin", "POST", data);
string tokens = Encoding.UTF8.GetString(bytes);
string authToken = extractAuthToken(tokens);
//-------------- Get page views -------------------
string feed = "https://www.google.com/analytics/feeds/data";
//Required:
string ids = "ga:xxxx";
string metrics = "ga:pageviews";
string startDate = "2011-06-25";
string endDate = "2011-07-25";
//Optional:
string dimensions = "ga:pagePath";
string sort = "-ga:pageviews";
string feedUrl = string.Format("{0}?ids={1}&dimensions={2}&metrics={3}&sort={4}&start-date={5}&end-date={6}",
feed, ids, dimensions, metrics, sort, startDate, endDate);
webClient.Headers.Add("Authorization", "GoogleLogin " + authToken);
string result = webClient.DownloadString(feedUrl);
//-------------- Extract data from xml -------------------
XDocument xml = XDocument.Parse(result);
var ns1 = "{http://www.w3.org/2005/Atom}";
var ns2 = "{http://schemas.google.com/analytics/2009}";
var q = from entry in xml.Descendants()
where entry.Name == ns1 + "entry"
select new
{
PagePath = entry.Element(ns2 + "dimension").Attribute("value").Value,
Views = entry.Element(ns2 + "metric").Attribute("value").Value
};
//-------------- Do something with data -------------------
foreach (var page in q)
{
Debug.WriteLine(page.PagePath + " " + page.Views);
}
//-------------- Help Method -------------------
private string extractAuthToken(string data)
{
var tokens = data.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
return tokens.Where(token => token.StartsWith("Auth=")).Single();
}

Categories