Error 401 authenticating with Project Online and CSOM - csom

I get error 401 (or 403) when trying to connect to Project Online with CSOM in a console app. (This is not on-premise. It is Microsoft Project Online 2013.) Here is the code.
ProjectContext projContext = new ProjectContext(pwaPath);
projContext.Credentials = new NetworkCredential("myUserID", "mypwd", "xxx.onmicrosoft.com");
projContext.ExecutingWebRequest += new EventHandler<WebRequestEventArgs>(projContext_ExecutingWebRequest);
projContext.Load(projContext.Projects);
projContext.ExecuteQuery();
**// Error 401 Unauthorized**
static void projContext_ExecutingWebRequest(object sender, WebRequestEventArgs e)
{
e.WebRequestExecutor.WebRequest.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
}
And another try, without ExecutingWebRequest:
ProjectContext projContext = new ProjectContext(pwaPath);
projContext.Credentials = new NetworkCredential("myUserID", "mypwd", "xxx.onmicrosoft.com");
projContext.Load(projContext.Projects);
projContext.ExecuteQuery();
**// Error 403 Forbidden**
Q1: Are there any problems with the code?
Q2: Is there a setting in Project Online that I'm missing?

You can use:
new SharePointOnlineCredentials(username, secpassword);
instead of
new NetworkCredential("admin#myserver.onmicrosoft.com", "password");
First: Install required Client SDK
SharePoint Client SDK :
http://www.microsoft.com/en-au/download/details.aspx?id=35585
Project 2013 SDK:
http://www.microsoft.com/en-au/download/details.aspx?id=30435
Second: add the reference to your project
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll
Microsoft.ProjectServer.Client.dll
You can find the dlls in %programfiles%\Common Files\microsoft shared\Web Server Extensions\15\ISAPI
and %programfiles(x86)%\Microsoft SDKs\Project 2013\REDIST
Here is sample code:
using System;
using System.Security;
using Microsoft.ProjectServer.Client;
using Microsoft.SharePoint.Client;
public class Program
{
private const string pwaPath = "https://[yoursitehere].sharepoint.com/sites/pwa";
private const string username ="[username]";
private const string password = "[password]";
static void Main(string[] args)
{
SecureString secpassword = new SecureString();
foreach (char c in password.ToCharArray()) secpassword.AppendChar(c);
ProjectContext pc = new ProjectContext(pwaPath);
pc.Credentials = new SharePointOnlineCredentials(username, secpassword);
//now you can query
pc.Load(pc.Projects);
pc.ExecuteQuery();
foreach(var p in pc.Projects)
{
Console.WriteLine(p.Name);
}
//Or Create a new project
ProjectCreationInformation newProj = new ProjectCreationInformation() {
Id = Guid.NewGuid(),
Name = "[your project name]",
Start = DateTime.Today.Date
};
PublishedProject newPublishedProj = pc.Projects.Add(newProj);
QueueJob qJob = pc.Projects.Update();
JobState jobState = pc.WaitForQueue(qJob,/*timeout for wait*/ 10);
}
}
I already answered this question in other question
How to authenticate to Project Online PSI services?

Related

ServiceNow integration with C# and dotnet core application

protected void Button1_Click(object sender, EventArgs e)
{
//Incident Service
IncidentService.ServiceNowSoapClient soapClient = new IncidentService.ServiceNowSoapClient();
soapClient.ClientCredentials.UserName.UserName = "username"; // username have SOAP role in SNow.
soapClient.ClientCredentials.UserName.Password = "Password1";
IncidentService.getRecords _getRecords = new IncidentService.getRecords();
IncidentService.getRecordsResponseGetRecordsResult[] getRecordsResponses = soapClient.getRecords(_getRecords);
_getRecords.active = true;
// Note: Please enable SOAP/REST services in your SNow dev instance table(s), Also,
// Go to system web services --> properties -> enable the 3rd option from the bottom.(This property sets the elementFormDefault attribute of the embedded XML schema to the value of unqualified)
//ServiceNowSoapClient client = new ServiceNowSoapClient();
//client.ClientCredentials.UserName.UserName = "username"; // username have SOAP role in SNow.
//client.ClientCredentials.UserName.Password = "Password1";
//insert newRecord = new insert();
//insertResponse insertResponse = new insertResponse();
//newRecord.first_name = "Jackson";
//newRecord.last_name = "Chris";
//newRecord.phone_number = "911-911-9999";
//newRecord.number = "CUS3048232";
try
{
//insertResponse = client.insert(newRecord);
//TextBox1.Text = insertResponse.sys_id;
getRecordsResponses = soapClient.getRecords(_getRecords);
for (int i = 0; i < getRecordsResponses.Length; i++)
{
TextBox2.Text = getRecordsResponses[i].short_description;
TextBox3.Text = getRecordsResponses[i].category;
}
}
catch (Exception ex)
{
TextBox1.Text = ex.Message;
}
//finally { client.Close(); }
}
How do you leverage ServiceNow data that reside in enterprise servicenow(CMDB,ITIL,various enterprise dbs, new dbs) dev,prod instances
to create End to End automated applications with C#, dotnetcore.
our goal is to Automate applications end to end with ServiceNow, dotnetcore, C#, docker containers, Ansible, Automic.
I know you probably don't need, maybe someone looking for the same finds this question.
I developed an library just for that.
https://emersonbottero.github.io/ServiceNow.Core/

EWS OAuth .net core 2.1

We have a solution today where we use EWS's basic authentication (username and password) with .net Core 2.1, and it works. The problem is that basic authentication will expire in 2020. Therefore, we will transition to the OAuth solution that will work after 2020.
We have tried multiple solutions for this problem, including this: https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth, but some of the methods have been updated (AcquireToken -> AcquireTokenAsync).
It's important that the authentication against azure is not client-based, since everything will happen in backend (web api).
Does anyone have a solution to this problem?
This is our current solution:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Credentials = new WebCredentials(<email>, <password>);
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
This is an example of what we have tried:
public class Program
{
public static void Run()
{
//tried this as well: string authority = "https://login.windows.net/<devAccountName>.onmicrosoft.com";
string authority = "https://login.microsoftonline.com/<tenantId>/OAuth2/Token";
string clientId = "<clientId>"; // Application ID from Azure
Uri clientAppUri = new Uri("http://localhost:55424/");
Uri resourceHostUri = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
AuthenticationResult authenticationResult = null;
AuthenticationContext authenticationContext = new AuthenticationContext(authority, false);
string errorMessage = null;
try
{
Console.WriteLine("Trying to acquire token");
PlatformParameters platformParams = new PlatformParameters(PromptBehavior.Auto);
authenticationResult = authenticationContext.AcquireTokenAsync("https://outlook.office365.com/EWS/Exchange.asmx", clientId, clientAppUri, platformParams).Result;
}
catch (AdalException ex)
{
errorMessage = ex.Message;
if (ex.InnerException != null)
{
errorMessage += "\nInnerException : " + ex.InnerException.Message;
}
}
catch (ArgumentException ex)
{
errorMessage = ex.Message;
}
if (!string.IsNullOrEmpty(errorMessage))
{
Console.WriteLine("Failed: {0}" + errorMessage);
return;
}
Console.WriteLine("\nMaking the protocol call\n");
ExchangeService exchangeService = new ExchangeService(ExchangeVersion.Exchange2013);
exchangeService.Url = resourceHostUri;
exchangeService.TraceEnabled = true;
exchangeService.TraceFlags = TraceFlags.All;
exchangeService.Credentials = new OAuthCredentials(authenticationResult.AccessToken);
exchangeService.FindFolders(WellKnownFolderName.Root, new FolderView(10));
}
}
We receive this error message after we log in:
AADSTS50001: The application named
https://outlook.office365.com/EWS/Exchange.asmx was not found in the tenant named <tenantId>. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.

app.config Xamarin pcl

I need to add some tag in a app.config file for implement a dll (xmlsoccer).
I have to add something like
<system.serviceModel>
<bindings>
<basicHttpBinding>
in a configuration node, but I don't know where it is.
I tried to create an app.config file and set DotNetConfig.xsd as scheme, but during compile, I have this errors:
WARNING: failed to load endpoint configuration for *
SyStem.InvalidOperationException: A Binding must be configured for this channel factory
can anyone help me?
I tried to write this:
` public class MainActivity : FormsApplicationActivity
{
public static readonly EndpointAddress EndPoint = new EndpointAddress("http://www.xmlsoccer.com/FootballDataDemo.asmx");
App application;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
// LoadApplication(new App(binding, EndPoint));
CreateBasicHttp();
LoadApplication(application);
}
private void CreateBasicHttp()
{
var binding = new BasicHttpBinding()
{
Name = "basicHttpBinding",
MaxReceivedMessageSize = 1000000,
};
binding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
{
MaxArrayLength = 2147483646,
MaxStringContentLength = 5242880,
};
var timeout = new TimeSpan(0, 1, 0);
binding.SendTimeout = timeout;
binding.OpenTimeout = timeout;
binding.ReceiveTimeout = timeout;
application = new App(binding, new EndpointAddress("http://www.xmlsoccer.com/FootballDataDemo.asmx"));
}`
in my MainActivity.cs, but obviously it isn't enough.
Still looking for answer?
Take a look here:
https://forums.xamarin.com/discussion/19303/how-to-consume-wcf-service-in-xamarin-forms-pcl
Steps:
1.- Opening a command prompt in Windows and using the SLSvcUtil.exe tool
from the Silverlight SDK to generate a proxy from a WSDL file. slsvcutil http://www.yourserver.com/WebServices/YourServiceSoapClient.asmx?WSDL /out:YourService.cs That utility is located at C:\Program Files (x86)\Microsoft SDKs\Silverlight\v5.0\Tools\ on my computer.
2.- Adding the resulting YourService.cs file to my project.
3.- Adding the following code to access the service:
// Create the WCF client (created using SLSvcUtil.exe on Windows)
YourServiceSoapClient client = new YourServiceSoapClient(
new BasicHttpBinding(),
new EndpointAddress("hhttp://www.yourserver.com/WebServices/YourServiceSoapClient.asmx"));
// Call the proxy - this should use the async versions
client.ServiceFunctionCompleted += OnGotResult;
client.ServiceFunctionAsync(parameter);
And the OnGotResult function:
void OnGotResult(object sender, ServiceFunctionCompletedEventArgs e)
{
Device.BeginInvokeOnMainThread(async () => {
string error = null;
if (e.Error != null)
error = e.Error.Message;
else if (e.Cancelled)
error = "Cancelled";
if (!string.IsNullOrEmpty(error))
{
await DisplayAlert("Error", error, "OK", "Cancel");
}
else
{
resultsLabel.Text = e.Result;
}
});
}

Example SNS subscription confirmation using AWS .NET SDK

I am trying to figure out how to use the AWS .NET SDK to confirm a subscription to a SNS Topic.
The subscription is via HTTP
The endpoint will be in a .net mvc website.
I can't find any .net examples anywhere?
A working example would be fantastic.
I'm trying something like this
Dim snsclient As New Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceClient(ConfigurationSettings.AppSettings("AWSAccessKey"), ConfigurationSettings.AppSettings("AWSSecretKey"))
Dim TopicArn As String = "arn:aws:sns:us-east-1:991924819628:post-delivery"
If Request.Headers("x-amz-sns-message-type") = "SubscriptionConfirmation" Then
Request.InputStream.Seek(0, 0)
Dim reader As New System.IO.StreamReader(Request.InputStream)
Dim inputString As String = reader.ReadToEnd()
Dim jsSerializer As New System.Web.Script.Serialization.JavaScriptSerializer
Dim message As Dictionary(Of String, String) = jsSerializer.Deserialize(Of Dictionary(Of String, String))(inputString)
snsclient.ConfirmSubscription(New Amazon.SimpleNotificationService.Model.ConfirmSubscriptionRequest With {.AuthenticateOnUnsubscribe = False, .Token = message("Token"), .TopicArn = TopicArn})
End If
Here is a working example using MVC WebApi 2 and the latest AWS .NET SDK.
var jsonData = Request.Content.ReadAsStringAsync().Result;
var snsMessage = Amazon.SimpleNotificationService.Util.Message.ParseMessage(jsonData);
//verify the signaure using AWS method
if(!snsMessage.IsMessageSignatureValid())
throw new Exception("Invalid signature");
if(snsMessage.Type == Amazon.SimpleNotificationService.Util.Message.MESSAGE_TYPE_SUBSCRIPTION_CONFIRMATION)
{
var subscribeUrl = snsMessage.SubscribeURL;
var webClient = new WebClient();
webClient.DownloadString(subscribeUrl);
return "Successfully subscribed to: " + subscribeUrl;
}
Building on #Craig's answer above (which helped me greatly), the below is an ASP.NET MVC WebAPI controller for consuming and auto-subscribing to SNS topics. #WebHooksFTW
using RestSharp;
using System;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Web.Http;
using System.Web.Http.Description;
namespace sb.web.Controllers.api {
[System.Web.Mvc.HandleError]
[AllowAnonymous]
[ApiExplorerSettings(IgnoreApi = true)]
public class SnsController : ApiController {
private static string className = MethodBase.GetCurrentMethod().DeclaringType.Name;
[HttpPost]
public HttpResponseMessage Post(string id = "") {
try {
var jsonData = Request.Content.ReadAsStringAsync().Result;
var sm = Amazon.SimpleNotificationService.Util.Message.ParseMessage(jsonData);
//LogIt.D(jsonData);
//LogIt.D(sm);
if (!string.IsNullOrEmpty(sm.SubscribeURL)) {
var uri = new Uri(sm.SubscribeURL);
var baseUrl = uri.GetLeftPart(System.UriPartial.Authority);
var resource = sm.SubscribeURL.Replace(baseUrl, "");
var response = new RestClient {
BaseUrl = new Uri(baseUrl),
}.Execute(new RestRequest {
Resource = resource,
Method = Method.GET,
RequestFormat = RestSharp.DataFormat.Xml
});
if (response.StatusCode != System.Net.HttpStatusCode.OK) {
//LogIt.W(response.StatusCode);
} else {
//LogIt.I(response.Content);
}
}
//read for topic: sm.TopicArn
//read for data: dynamic json = JObject.Parse(sm.MessageText);
//extract value: var s3OrigUrlSnippet = json.input.key.Value as string;
//do stuff
return Request.CreateResponse(HttpStatusCode.OK, new { });
} catch (Exception ex) {
//LogIt.E(ex);
return Request.CreateResponse(HttpStatusCode.InternalServerError, new { status = "unexpected error" });
}
}
}
}
I don't know how recently this has changed, but I've found that AWS SNS now provides a very simply method for subscribing that doesn't involve extracting urls or building requests using RESTSharp.....Here's the simplified WebApi POST method:
[HttpPost]
public HttpResponseMessage Post(string id = "")
{
try
{
var jsonData = Request.Content.ReadAsStringAsync().Result;
var sm = Amazon.SimpleNotificationService.Util.Message.ParseMessage(jsonData);
if (sm.IsSubscriptionType)
{
sm.SubscribeToTopic(); // CONFIRM THE SUBSCRIPTION
}
if (sm.IsNotificationType) // PROCESS NOTIFICATIONS
{
//read for topic: sm.TopicArn
//read for data: dynamic json = JObject.Parse(sm.MessageText);
//extract value: var s3OrigUrlSnippet = json.input.key.Value as string;
}
//do stuff
return Request.CreateResponse(HttpStatusCode.OK, new { });
}
catch (Exception ex)
{
//LogIt.E(ex);
return Request.CreateResponse(HttpStatusCode.InternalServerError, new { status = "unexpected error" });
}
}
The following example helped me work with SNS. It goes through all the steps to work with Topics. The subscribe request in this case is an email address, however that can be changed to HTTP.
Pavel's SNS Example
Documentation
I ended up getting it working using the code shown. I was having trouble capturing the exception on the development server which turned out was telling me the server's time didn't match the timestamp in the SNS message.
Once the server's time was fixed up (an Amazon server BTW), the confirmation worked.

Creating a process in ASP.NET MVC controller

I have a requirement to run an application through my MVC controller. To get the installation path I used following link (I used answer provided by Fredrik Mörk). It worked and I could able to run the exe through a process. The problem occurred when I deployed this solution on IIS where it did not create the process as it was creating in local dev environment. Can anybody tell me how to create a windows process through a solution which is hosted on IIS ?
private string GetPathForExe(string fileName)
{
private const string keyBase = #"SOFTWARE\Wow6432Node\MyApplication";
RegistryKey localMachine = Registry.LocalMachine;
RegistryKey fileKey = localMachine.OpenSubKey(string.Format(#"{0}\{1}", keyBase, fileName));
object result = null;
if (fileKey != null)
{
result = fileKey.GetValue("InstallPath");
}
fileKey.Close();
return (string)result;
}
public void StartMyApplication()
{
Process[] pname = Process.GetProcessesByName("MyApplication");
if (pname.Length == 0)
{
string appDirectory = GetPathForExe("MyApplication");
Directory.SetCurrentDirectory(appDirectory);
ProcessStartInfo procStartInfo = new ProcessStartInfo("MyApplication.exe");
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process proc = new Process();
proc.StartInfo = procStartInfo;
proc.Start();
}
}

Resources