Excel Services in SharePoint Online - c#

I have a working code using Excel Services published on on-premises SharePoint:
var _service = new ExcelService { UseDefaultCredentials = true };
Status[] _status;
var _sessionId = _service.OpenWorkbookForEditing("http://<sharepoint url>/<list>/<file>.xlsx", "en-US", "en-US", out _status);
ExcelService is a valid web reference pointing to http://<sharepoint url>/_vti_bin/excelservice.asmx
However, the same code doesn't work when using the Excel Services on SharePoint Online.
I am able to get the API version:
_service.GetApiVersion(out _status);
Excel Web Services (16.0)
But opening a workbook throws a SoapException:
We couldn't find the file you wanted.
I tried passing the credentials:
var _pass = new SecureString();
foreach (char _c in "<SP Online password>".ToCharArray()) { _pass.AppendChar(_c); }
var _cred = new SharePointOnlineCredentials("<SP Online login>", _pass);
var _service = new ExcelService { Credentials = _cred };
And the credentials seem to be valid, i.e. this code works:
// login test
using (ClientContext _sp = new ClientContext("<SP Online url>") { Credentials = _cred })
{
var _web = _sp.Web;
_sp.Load(_web);
_sp.ExecuteQuery();
Console.WriteLine(_web.Title);
}
What am I missing?
It seems it's an authentication issue but it's hard to tell since the error message is pretty opaque. How can I find out more details about the error?
Are Excel Services exposed only for specific licences?
Note, I am able to use Excel REST API but that doesn't work in my scenario (heavy editing).

Related

Token failed : 401 Forbidden Error connecting to Sharepoint using pnpframework

I am writing a web app that I would like to have access to Sharepoint Document Libraries from a particular site using the currently logged on user credentials. I have looked at a number of articles that suggest using the PnP Framework and using a certificate instead of the client/secret ids.
I have tried both, the code of which is below:
string siteCollectionURL = "https://mycompanyname.sharepoint.com/sites/staffportal";
var authManager = new AuthenticationManager(ApplicationId, "C:\\pathtopfxfile\certifcatefx.pfx", "certificatepassword", "https://mycompany.sharepoint.com/sites/staffportal");
using (var clientContext = authManager.GetACSAppOnlyContext(siteCollectionURL,ApplicationId,ClientSecretId))
{
clientContext.Load(clientContext.Web, p => p.Title);
clientContext.ExecuteQuery();
return Ok(clientContext.Web.Title);
}
Unfortunately on the ExecuteQuery line I am consistently getting the 401 error, indicating that I am not authorized.
I registered the app in Azure -> Enterprise applications:
I have checked the following articles:
How to use the PnP Framework in a c# application
Secure Authentication of SharePoint with PnP Framework with C#(Code)
And tried the code snippets, but I cannot seem to find anything that suggests using the currently logged in user to the Web app.(see screen shot) - the user is a global administrator
Below is the error:
Any suggestions would be much appreciated.
Regards,
Darren
UPDATE TO ARTICLE
jimas13's link is what pointed me in the right direction. The tweaks I mentioned in the comment I have posted below for anyone wanting to write an MVC C# web app. This does require that the app needs to be registered and needs a self-signed certificate setup.
The two Async lines need to be written as follows:
public static async Task<AuthenticationResult> GetToken(IConfidentialClientApplication app, string[] scopes)
{
return await app.AcquireTokenForClient(scopes).ExecuteAsync();
}
public static async Task<Web> GetClientContext(string Uri,AuthenticationResult authResult)
{
using (var clientContext = ContextHelper.GetClientContext(Uri, authResult.AccessToken))
{
Web web = clientContext.Web;
clientContext.Load(web);
await clientContext.ExecuteQueryAsync();
return web;
}
}
The rest of the code is here:
public IActionResult Index()
{
AuthenticationConfiguration.AuthenticationConfiguration config = AuthenticationConfiguration.AuthenticationConfiguration.ReadFromJsonFile("appsettings.json");
string siteURL = config.SiteUrl;
string[] scopes = new string[] { config.Scope };
CertificateDescription certificate = config.Certificate;
ICertificateLoader certificateLoader = new DefaultCertificateLoader();
certificateLoader.LoadIfNeeded(certificate);
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithCertificate(certificate.Certificate)
.WithTenantId(config.Tenant)
.WithAuthority(config.Authority)
.Build();
AuthenticationResult result = GetToken(app, scopes).Result;
Web WebSite = GetClientContext(siteURL, result).Result;
return Ok(WebSite.Title);
}
The .SiteUrl and .Scope were added to the AuthenticationConfiguration.cs file as a property and then also added to the appsettings.json file.

Web service consumption with oAuth2

AS you will see, I'm not an expert developing webApps, but I've done one that connects with the web services of Business Central (BC).
Inside visual studio, I added the web service as a service reference, and the authentication is user/password. This is how the call to the WS is done:
protected void ValidateEmployee()
{
var appSettings = ConfigurationManager.AppSettings;
string user = appSettings["user"].ToString();
string pswd = appSettings["pswd"].ToString();
string WHS_MGMT = appSettings["WHS_MGMT"].ToString();
string ItemTRacking = appSettings["ItemTRacking"].ToString();
WHS_MGMT ws = new WHS_MGMT();
ws.Credentials = new System.Net.NetworkCredential(user, pswd);
ws.Url = WHS_MGMT;
String codOperario = txtCodigo.Text.ToUpper();
string userPswd = txtPSWD.Text;
if (ws.Login(codOperario, userPswd))
{
Response.Redirect("Default.aspx?codOperario=" + codOperario);
}
else
{
lblOpIncorrecto.Text = "Operario/contraseƱa incorrecto";
lblOpIncorrecto.Visible = true;
}
}
But in nest weeks, we will be forces to use oAuth2 authentication to call BC web services. I've found several tips to get the token, and at first, doesn't seem to be a problem (at first...). But he main problem is that I don't know how to apply or use that token into the call to the WS. I even don't know it adding the WS as a service reference is the best way to do it...
Any tip will be realy welcomed
Thank you all

Awssdk works on .net dotnetcore (IAM and GatewayAPI) but throws Amazon.CognitoIdentity.Model.NotAuthorizedException on Xamarin Android APP

I have a problem with Awssdk lib from Amazon that I can't understand.
I made an easy Class to authorized and obtain resources from Amazon.
It uses the configuration from user sessionConfig: clientId, identitypoolId,userpoolId, username, password, secret.
And also the request config (signRequest) host, absolutpath, method, region.
var client = AmazonClient(sessionConfig, requestconfig);
With this I can easyly
client.GetClientTokens();
That makes a call to CognitoAuth userpools:
var cred = new CognitoAWSCredentials(_sessionConfig.IdentityPoolId,` RegionEndpoint.EUCentral1);
var provider = new AmazonCognitoIdentityProviderClient(cred, RegionEndpoint.EUCentral1);
CognitoUserPool userPool = new CognitoUserPool(_sessionConfig.UserPoolId, _sessionConfig.ClientId, provider);
CognitoUser user = new CognitoUser(_sessionConfig.UserPoolId, _sessionConfig.ClientId, userPool, provider, _sessionConfig.Secret, _sessionConfig.UserName);
var authRequest = new InitiateSrpAuthRequest()
{
Password = _sessionConfig.Password
};
AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
Then I just call
client.GetApiResource(absolutpath);
And I can get with this auth info the resource from the api.
_requestConfig.AbsolutePath = absolutePath;
//Signmethod from Amazon
GetSignedRequest();
var responses = _webRequest.GetResponse();
var result = responses.GetResponseStream();
var data = string.Empty;
using (var sr = new StreamReader(result))
{
data = sr.ReadToEnd();
}
return data;
This code works like a charm on my dotnetcore console app, I become tokens access data and user or other api resources.
When I want to use it on a Xamarin.Android solution.
I become, when trying to get the credentials:
user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
Amazon.CognitoIdentity.Model.NotAuthorizedException: Access to
Identity 'eu-central-1:xxxxxxxxxxxxxxxxxxxxx' is forbidden.
System.Net.HttpStatusCode.BadRequest
errorCode "NotAuthorizedException"
The only thing I could see it is different is the UserAgent from provider config:
console program:
aws-sdk-dotnet-coreclr/3.3.11.22 aws-sdk-dotnet-core/3.3.29.12 .NET_Core/4.6.26606.02 OS/Microsoft_Windows_10.0.14393
Xamarin.Android app:
aws-sdk-dotnet-pcl/3.3.4.3 aws-sdk-dotnet-core/3.3.29.13 Mono/5.10.1(tarball) OS/ANDROID_7.0 PCL/Xamarin.Android
Console works xamarin throw this exception. Any ideas?

Why does SPContext.Current return a null value?

I am new in SharePoint development and I am developing a custom SharePoint Farm Solution. I am currently having an issue with code which runs properly on the production and test environments but gives an error on the development and I don't know why. The source code looks identical in all environments. I was able to locate the error through debugging and I found that it gives an error on the following line:
SPWeb web = SPContext.Current.Web;
The code is about sending an email upon the completion of course evaluation function in my application. Here's the code:
MailConfiguration config = new MailConfiguration();
MailNotification content = config.GetMailNotification(userId, courseId);
SPWeb web = SPContext.Current.Web;
string subject = content.Subject;
string msgBody = content.Body;
SPSecurity.RunWithElevatedPrivileges(delegate ()
{
bool result = SPUtility.SendEmail(web, appendHtmlTag, htmlEncode, content.To, subject, msgBody);
message = "Email sent successfully";
});
Could you please explain to me why this is happening? The SendEmail function is not working now due to this error.
Check the follows:
1.Check the alternate mapping access(AAMs). If not, configure it.
2.Check if have Site Collection at the root of the SharePoint website.
3.Use the method below to create a fake SPContext in a non-SharePoint context.
public static SPContext FakeSPContext(SPWeb web)
{
if (HttpContext.Current == null)
{
HttpRequest request = new HttpRequest("", web.Url, "");
HttpContext.Current = new HttpContext(request, new HttpResponse(TextWriter.Null));
}
if (HttpContext.Current.Items["HttpHandlerSPWeb"] == null)
{
HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
}
return SPContext.Current;
}

Google account issue - Cannot write on the spreadsheet

I m developing an App which has to write on google spreadsheet.
My application used to work fine until Google changed is Auth API two months ago.
Following the link with the new process.
Google.GData.Client.GDataRequestException - Authentication suddenly fails in old code
I have a google account me#company.com which is managed by my boss account company#gmail.com.
I want to write in a spreadsheet named "Bank Details" shared to me from my boss account.(the onwer is "mycompany")
I generated a key.p12 from my account and it works fine, I can write.
Now the strange things is when i create a spreadsheet by myself (the owner is "me", my app doesn t find the file and return an error message.
I generated a key.p12 from my boss account and it still doesn't find the spreadsheet created by my boss, so from his point of view the owner is "me".
In conclusion:
I find the spreadsheet shared by my boss with my key and I can write in it.
I don't find the file created by me with my key.
My app doesn't find the file created by my boss with his key.
Here my code but i don't think the problem comes from here.
string keyFilePath; // found in developer console
string serviceAccountEmail;
if (test == true)
{
keyFilePath = #"C:\keyTEST.p12";
serviceAccountEmail = "me#developer.gserviceaccount.com";// found in developer console
}
else
{
keyFilePath = #"C:\key.p12";
serviceAccountEmail ="company#developer.gserviceaccount.com";
}
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) //create credential using certificate
{
Scopes = new[] { "https://spreadsheets.google.com/feeds/" } //this scopr is for spreadsheets, check google scope FAQ for others
}.FromCertificate(certificate));
credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait(); //request token
var requestFactory = new GDataRequestFactory("Some Name");
requestFactory.CustomHeaders.Add(string.Format("Authorization: Bearer {0}", credential.Token.AccessToken));
SpreadsheetsService myService = new SpreadsheetsService("Bank Details"); //create your old service
myService.RequestFactory = requestFactory; //add new request factory to your old service
myService.setUserCredentials(email, password);
// Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
SpreadsheetQuery query = new SpreadsheetQuery();
// Make a request to the API and get all spreadsheets.
SpreadsheetFeed feed = myService.Query(query);
SpreadsheetEntry fileEntry = feed.Entries.Cast<SpreadsheetEntry>().FirstOrDefault(entry => entry.Title.Text == spreadSheetName);
SpreadsheetEntry spreadsheet = (SpreadsheetEntry)fileEntry;
if (feed.Entries.Count == 0)
{
Console.WriteLine("None");
}
...
You need share in your sheet the e-mail "company#developer.gserviceaccount.com" or "me#developer.gserviceaccount.com".

Categories