Connect with Visual Studio 2012 and C sharp to microsoft cloud TFS server - visual-studio-2012

I am building an asp.net webforms site that can connect to our tfs hosted on Microsoft (http://companyname.visualstudio.com) and get data from it. When I run the project with Cassini it runs fine as it gets the authentication from the browser. But I want to do this from code behind.
I have tried various setups like
var tfs = new TfsTeamProjectCollection(CollectionUri, new UICredentialsProvider());
[which is now deprecated as method and should not be used]
or
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(CollectionUri);
or even with
var tfs = new TfsTeamProjectCollection(CollectionUri, new NetworkCredential("windowsliveid","password"));
I have no domain since it is a Windows Liveid
and then
tfs.EnsureAuthenticated();
Also I get the uri through
var CollectionUri = new Uri("https://companyname.visualstudio.com/DefaultCollection/");
Any ideas on how to properly authenticate. I would love to either prompt the auth window or give username and password directly.
------------------------------ SOLVED !!! ---------------------------------
Here is the solution to it after some googling following Martin Woodward's very helpful suggestion.
First alternate credentials have to be activated through the TFS account. Then the code can be changed into this which works fine :)
Just remember that you need to have the latest version of VS 2012 (at least update1) for the code to work. Else you can't reference BasicAuthCredential.
var nc = new NetworkCredential("username", "password");
var bc = new BasicAuthCredential(nc);
var tfsc = new TfsClientCredentials(bc) {AllowInteractive = false};
var tfs = new TfsTeamProjectCollection(CollectionUri, tfsc);
tfs.Authenticate();
And here are the referenced dlls.
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

Take a look at service credentials, or try enabling alternate credentials on your account which will then allow you to authenticate using http basic auth.
You probably want service credentials for what it sounds like you are doing though.

Related

Automating SharePoint scripts/code with LegacyAuthProtocolsEnabled set to false

We use the Microsoft.SharePoint.Client library to automate SharePoint work from our workflow engine but yesterday, one of our client informed us they wanted to disable the Legacy Authentication (LegacyAuthProtocolsEnabled to false).
Once I tried it on our end, I ended up getting an Unauthorised exception.
All in good wanting to disable the Legacy Authentication for obvious security reason, but the problem with the Modern Authentication is that it requires user interaction which is clearly not a solution since we are running tasks in the background.
I've been googling this for quite some time but I haven't found a solution as of yet on how to handle automatic authentication for background work.
Is there a way to "authenticate" to SharePoint without any user interaction while LegacyAuthProtocolsEnabled is set to false?
I found an article that suggested using the App Authentication but after reading more about it, I believe this is considered an old method to authenticate and is likely to be deprecated as well over time, but I thought I'd still give it a go just in case but it did not work. When I got to
https://tenant.sharepoint.com/_layouts/15/appregnew.aspx
Where tenant is our company domain name, and I click on the "Create" button after filling in all the relevant fields, I get the following error, which is completely useless:
Sorry, something went wrong
An unexpected error has occurred.
TECHNICAL DETAILS
According to this article HOW TO HARDEN YOUR SHAREPOINT ONLINE ENVIRONMENT BY DISABLING LEGACY AUTHENTICATION, Legacy Authentication was no longer be an option as of the 13/10/2020, yet here we are, and the option is still available in SharePoint 365 and while the article is interesting explain why Legacy Authentication should be switched off, etc... it does not get into any details as to how automated solutions should be handled.
Also found an old thread "LegacyAuthProtocolsEnabled" and Scripted Logons to SharePoint Online? where #DeanWang suggests leaving it turned on as:
All custom CSOM, PowerShell code will stop working
This may also prevent third-party apps from accessing SharePoint
Online resources.
I'm going to stop here as I could keep going and the question is already too long for my liking and bottom line is, does anyone know if there is a way, and what is the best way, to authenticate to SharePoint while running automated "scripts/code" from a background task without requiring any user interaction while the Legacy Authentication is switch off?
Thanks
Update-1
After reading articles after articles, I've yet to connect to SharePoint 365.
I also spend more time on the PnP Framework as recommended by numerous articles. I created a dummy app with the following sample code which is used again in various articles, including this one:
Secure Authentication of SharePoint with PnP Framework with C#(Code)
My code is identical as you can see:
var clientContext = new AuthenticationManager().GetACSAppOnlyContext(
"https://mycompany.sharepoint.com/sites",
"MyClientid",
"MySecretId");
using (clientContext)
{
//Get Lists
var web = clientContext.Web;
var lists = web.Lists;
clientContext.Load(lists);
clientContext.ExecuteQuery();
foreach (var list in lists)
{
}
}
And even though I've granted full control in Azure for the specific test app that's using the specific ClientId and SecretId
I'm still getting the following error (401 - unauthorized):
System.Exception
HResult=0x80131500
Message=Token request failed.
Source=PnP.Framework
StackTrace:
at SharePointPnP.IdentityModel.Extensions.S2S.Protocols.OAuth2.OAuth2S2SClient.Issue(String securityTokenServiceUrl, OAuth2AccessTokenRequest oauth2Request) in /_/src/lib/PnP.Framework/Utilities/OAuth/OAuth2S2SClient.cs:line 18
at PnP.Framework.Utilities.TokenHelper.GetAppOnlyAccessToken(String targetPrincipalName, String targetHost, String targetRealm) in /_/src/lib/PnP.Framework/Utilities/TokenHelper.cs:line 116
at PnP.Framework.Utilities.ACSTokenGenerator.GetToken(Uri siteUrl) in /_/src/lib/PnP.Framework/Utilities/ACSTokenGenerator.cs:line 37
at PnP.Framework.AuthenticationManager.<GetContextAsync>b__59_0(String site) in /_/src/lib/PnP.Framework/AuthenticationManager.cs:line 971
at PnP.Framework.AuthenticationManager.<>c__DisplayClass75_0.<GetAccessTokenContext>b__0(Object sender, WebRequestEventArgs args) in /_/src/lib/PnP.Framework/AuthenticationManager.cs:line 1336
at Microsoft.SharePoint.Client.ClientRuntimeContext.OnExecutingWebRequest(WebRequestEventArgs args)
at Microsoft.SharePoint.Client.ClientContext.FireExecutingWebRequestEventInternal(WebRequestEventArgs args)
at Microsoft.SharePoint.Client.ClientContext.GetWebRequestExecutor()
at Microsoft.SharePoint.Client.ClientContext.GetFormDigestInfoPrivate()
at Microsoft.SharePoint.Client.ClientContext.EnsureFormDigest()
at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()
at ConsoleApp5.Program.Main(String[] args) in C:\Users\myuser\source\repos\ConsoleApp5\ConsoleApp5\Program.cs:line 23
This exception was originally thrown at this call stack:
[External Code]
SharePointPnP.IdentityModel.Extensions.S2S.Protocols.OAuth2.OAuth2WebRequest.GetResponse() in OAuth2WebRequest.cs
SharePointPnP.IdentityModel.Extensions.S2S.Protocols.OAuth2.OAuth2S2SClient.Issue(string, SharePointPnP.IdentityModel.Extensions.S2S.Protocols.OAuth2.OAuth2AccessTokenRequest) in OAuth2S2SClient.cs
Inner Exception 1:
WebException: The remote server returned an error: (401) Unauthorized.
Is there another section I should be looking at (and change) in the App Registration in Azure
Since it's the SharePoint Online that we are talking about, one easy way to connect to different SharePoint Sites is by using the Azure AD App-Only approach and since you are talking about a Deamon Service you can easily use Application Permissions when registering the App Registration.
You can, and you should, read more about it from the linked Microsoft Docs article.
You can also loggin via certificate or app registration secret as it is discribed in the Log in to Microsoft 365 in order to create automated CI CD SPFx pipelines, for example.
Hope the above helps, if not feel free to ask :)
Update: Please read below in order to have a better understanding.
Firstly, in your code segment you are using a wrong method from the PnP.Framework package.
AuthenticationManager().GetACSAppOnlyContext()
The above method refers to a completely different method of obtaining an authentication token, more specifically the Sharepoint App-Only model, which... well.... more or less is not being used nowadays quite so ofte. I think I read somewhere that MS is thinking of retiring this kind of Authentication and going onwards on the path of Azure Active Directory authentication, but, unfotunately, I cannot seem to find the link.
Furthermore, I have collected three projects and uploaded them to github for you to see. You can simply clone the repo and run the projects as-is from HERE.
As you will be able to see for yourself, there are three projects in the solution, which you can run each one individually from VSCode or Vs.
More in detail:
ConsoleApp1
(sorry for the name but forgot to switch it :) )
This is a Deamon Console Project that references the PnP.Framework namespace and tries to utilize all of the goodies that the good folks form the PnP Community have contributed.
The procedure is straight forward and is the same for all three projects ->
Read the AppConfiguration
Request the Access Token with appropriate scopes (Depending the service that i am referencing)
Declare the Token to be used by our Client Context.
In the PnP.Framework-related project the above cycle can be seen as below
AuthenticationConfiguration config = AuthenticationConfiguration.ReadFromJsonFile("appsettings.json");
var authManager = new PnP.Framework.AuthenticationManager(config.ClientId, config.Certificate.CertificateDiskPath, config.Certificate.CertificatePassword, config.Tenant);
using (var cc = authManager.GetAccessTokenContext("https://<REPLACE:name of tenant>.sharepoint.com/sites/testsite2", (string siteURL) => authManager.GetAccessToken(siteURL)))
ConsoleAppMSGraph
As the name suggests this Deamon Console App utilizes GraphServiceClient graphClient in order to get all the information that you request through the graph endpoint.
Subsequntly, you will notice that for this porject the scope name changes to
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
In addition, we request a collection of all the lists that currently reside in our SharePoint Root Site with the below segment:
var lists = await graphClient.Sites["root"].Lists
.Request()
.GetAsync();
ConsoleAppSPClient
This app is the default and most simple way of accessing data on Sharepoint.
The projects utilizes MSAL.Net and Microsoft.Sharepoint.Client namespaces in order to fetch an access token and, subsequently, embed that token in all our next requests.
In order to keep the answer a bit short, please refer to here in order to see how we initiate a Confidential App Client, request for a token and, later on, embedd it in our ClientContext object.
Notes
I have listed in the Readme.md of the repo, which permissions you should give to your app registration. You can view them Here.
I am using the Sites.FullControl.All but you can narrow down the list of sites that the app registration will have access by using the Sites.Selected.
All of the above projects, reference a common class library that serves as a strongly typed configuration object.
IMPORTANT you should always use a certificate to authenticate the client app as it is mentioned here. The previous link also describes the way you can create a certificate and upload it to the store of the app registration.
Amazing! Thank you very much #Jimas13. For the last 2 weeks I was struggling to find solution to my problem!! You saved me!! If you ever been in Greece let me buy you a drink!

SOAP NTLM login using .net core 2.1.300 failed on Ubuntu

I recently need to use .net core to do SOAP NTLM login.. to my horror.. I realized ,net core does not come with SOAP support.. fumbling around, I came across SOAPCore on nuget package which has SOAP middleware for .net core. My console app interfacing to .net core 2.1 SDK tries to do NTLM login. Below is the codes, very simple.. it's trying to login to Milestone VMS.
<----------codes--------------->
int MAX_BUFFERSIZE = 2 * 1024 * 1024;
string strURL = "http://192.168.51.207/ServerAPI/ServerCommandService.asmx";
BasicHttpBinding httpBinding = new BasicHttpBinding();
httpBinding.MaxBufferSize = MAX_BUFFERSIZE;
httpBinding.MaxReceivedMessageSize = MAX_BUFFERSIZE;
httpBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm; //changed Ntlm to Windows also don't help
EndpointAddress endpoint = new EndpointAddress(strURL);
var factory = new ChannelFactory(httpBinding, endpoint);
CredentialCache cc = new CredentialCache();
NetworkCredential ntcc = new NetworkCredential("user", "password", "domain");
cc.Add(strURL, 80, "ntlm", ntcc);
factory.Credentials.Windows.ClientCredential = cc.GetCredential(strURL, 80, "ntlm");
var client = factory.CreateChannel();
Guid guid = Guid.NewGuid();
LoginInfo lo = client.Login(guid, "");
Console.Write("\ntoken=" + lo.Token);
ConfigurationInfo config = client.GetConfiguration(lo.Token);
... //do something
client.Loguout(guid, lo.Token); //logout
<-------------end of code segment------------>
Now, running this in Windows 10 works fine.. it's able to login and get the info needed.. but funny thing is when it runs on Linux.. I installed BASH for Windows 10 and it's Ubuntu 18.04, and have installed .net core 2.1.300.. it gave an http code 401 exception: "The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'Negotiate, Ntlm'."
I've previously read on Stackoverflow about something quite similar and it was said that .net core 2.1 would resolve it.. I'm already using 2.1.300. Is it still not resolved? or am I doing something wrong?
Another question I have pertaining to this, the "ServerCommandServiceSoap" interface is generated using svcutil.exe from the wsdl file provided by Milestone in their SDK. Now, what is the difference between svcutil.exe and wsdl.exe? I noticed that the proxy class generated isn't the same usi ng these two tools.. using svcutil.exe has an interface class with dependencies on System.ServiceModel, while using wsdl.exe has no interface class and depends on System.Web.Services which is not available in .net core. why is it different when they are ran against the same wsdl document?
Can someone please enlighten me on this? thanks a lot.. :)

Latest Nugets for Outlook REST API?

I want to send emails from my .NET 4.6.1 application using one of our organisation's O365 email accounts. I'm wondering if there's a Nuget package which can help me.
Microsoft.Office365.OutlookServices looks a bit out-of-date, and the comments on the project page don't inspire confidence.
Microsoft.Graph seems more recent, but its code samples use the pre-release Microsoft Authentication Library (MSAL), which it says isn't suitable for production. Maybe I can use Active Directory Authentication Library .NET (ADAL) instead in conjunction with Graph?
The graph library is the official SDK. It is linked from the official Samles and SDKs page.
Even though the MSAL is described as pre-release on the NuGet page, the Github project page describes the Nuget as being from the stable branch.
Your mileage with it may vary, however in my projects I haven't had any issues with the 1.0.304142221-alpha NuGet.
Someone from Microsoft could probably shed some light on it, perhaps come with an indication of a release date of a non-preview NuGet?
For just sending mails, you can use System.Net.Mail like this:
var mailMessage = new MailMessage();
mailMessage.To.Add(new MailAddress(RECEIVER_MAIL_ADDRESS));
mailMessage.From = new MailAddress(SENDER_MAIL_ADDRESS, SENDER_NAME);
mailMessage.Subject = SUBJECT;
mailMessage.Body = BODY;
mailMessage.IsBodyHtml = true;
using (var smtp = new SmtpClient("smtp.office365.com", 587))
{
var credential = new NetworkCredential
{
UserName = USERNAME,
Password = PASSWORD,
Domain = DOMAIN_OPTIONAL
};
smtp.Credentials = credential;
smtp.EnableSsl = true;
smtp.TargetName = "";
await smtp.SendMailAsync(mailMessage);
}

Unable to add a service reference to Dynamics 365 crm in visual studio 2012

I am trying to add service reference to Dynamics 365 CRM using the following API https://[Organization].api.crm8.dynamics.com/api/data/v8.2/ but each time I am getting this window that asks me for credentials....
I tried using the credentials that I use to login to the crm...but they donot work...can someone tell me which credential I should use?..
Why exactly are you trying to add a reference to the CRM web services? Assuming you want to access CRM from server side code, what you need to do is:
Add references to the core CRM SDK assemblies (Microsoft.Crm.Sdk.Proxy.dll and Microsoft.Xrm.Sdk.dll). You get can them from the downloadable SDK or just add the "Microsoft.CrmSdk.CoreAssemblies" NuGet package.
After doing this you'll be able to write code "talking" with CRM. But what you are missing is the actual "connection". There are several ways of obtaining it, but the easiest one is to use the Xrm Tooling helper class, described here - https://msdn.microsoft.com/en-us/library/mt608573.aspx. You'll need to reference the required assemblies or use the "Microsoft.CrmSdk.XrmTooling.CoreAssembly" NuGet package.
After doing all this, you'll be able to successfully code against Dynamics CRM.
CrmServiceClient crmSvc = new CrmServiceClient(ConfigurationManager.ConnectionStrings["MyCRMServer"].ConnectionString);
IOrganizationService orgService = crmSvc.OrganizationServiceProxy;
// Who am I?
WhoAmIResponse whoAmIResp = orgService.Execute(new WhoAmIRequest()) as WhoAmIResponse;
Guid myUserId = whoAmIResp.UserId;
// Get all accounts starting with 'A'
QueryExpression query = new QueryExpression("account");
query.ColumnSet = new ColumnSet("accountid", "name");
query.Criteria.AddCondition("name", ConditionOperator.BeginsWith, "a");
EntityCollection ecoll = orgService.RetrieveMultiple(query);
foreach(Entity account in ecoll.Entities)
{
if(account.Attributes.Contains("name"))
{
Console.WriteLine((string)account["name"]);
}
}
// Update some account
Entity accountToUpdate = new Entity("account");
accountToUpdate["accountid"] = new Guid("_some_guid_here");
accountToUpdate["name"] = "new name";
orgService.Update(accountToUpdate);
If you want to use the type safe approach, you'll need to generate a proxy class - like described here: https://msdn.microsoft.com/en-us/library/gg327844.aspx
Afterwards you'll be able to write code like this:
DataContext data = new DataContext(orgService);
// DataContext is the name of the service context, as defined in the CrmScv tool
var myAccountData = (from a in data.AccountSet
where a.Address1_Telephone1 == "12312313"
select new
{
a.AccountId,
a.Name,
a.EMailAddress1,
a.PrimaryContactId
}).First();
Contact contactToUpdate = new Contact()
{
ContactId = myAccountData.PrimaryContactId.Id,
EMailAddress1 = myAccountData.EMailAddress1
};
orgService.Update(contactToUpdate);
... which is much nicer and less error prone.
From the looks of it you are trying to authenticate through an App outside of the context of Dynamics 365. If you want to authenticate with the Web API this way you will have to connect to Microsoft Dynamics 365 web services using OAuth and authenticate using ADAL
https://msdn.microsoft.com/en-us/library/gg327838.aspx
Here is a walkthrough on how to do it
https://msdn.microsoft.com/en-us/library/mt622431.aspx
Additional note:
If you are using CRM 2013 SDK you may need to update to 6.1.2 for Dynamics 365 Support
https://blogs.msdn.microsoft.com/crm/2017/02/01/dynamics-365-sdk-backwards-compatibility/

Log in to CRM from ASP.NET

I'm writing an application in which I have to log on to a CRM 2011 server from ASP.NET code. I quickly found this article:
http://msdn.microsoft.com/en-us/library/cc156363.aspx
The problem I'm having is in this bit of code from that article:
//Create the Service
CrmService service = new CrmService();
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
service.CrmAuthenticationTokenValue = token;
service.Url = crmurl;
Visual Studio can't resolve CrmService. So I tried to add a web reference to this project and point the web reference at the CRM service I'm using. The URL I'm getting from Settings->Customizations in CRM, and I'm using the Organization Service endpoint. However, after I add that reference CrmService is still unresolvable. What am I doing wrong?
First off, you have linked a CRM 4 MSDN article, some things have changed so you might want try this one instead: Authenticate Users with Microsoft Dynamics CRM Web Services.
Then as an alternative you may want to try the CrmConnection class, its a helper library in Microsoft.Xrm.Client. It means you can use a connection string approach to authenticate with CRM (and let the class takes care of all the hard work).
var connection = CrmConnection.Parse("Url=http://crm.contoso.com/xrmContoso; Domain=CONTOSO; Username=jsmith; Password=passcode;");
var service = new OrganizationService(connection);
var context = new CrmOrganizationServiceContext(connection);
You can also keep the connection strings in config files makes life significantly easier.
Related articles:
Simplified Connection to Microsoft Dynamics CRM.
Sample: Simplified Connection Quick Start using Microsoft Dynamics CRM.
If you're using standard AD authentication with a local environment this answer should work fine: How to Authenticate to CRM 2011?
Actually, the login procedure is heavily dependent on the authentication provider you're targeting. I'm currently in the process of structuring that info in a pedagogic way on my blog so you're welcome to check it out and nag if it's too techy.
There are at the moment four such ways.
Active directory
Live id
Federation
Online federation
Which is applicable in your case, you should know already. If not, there's code for that too uploaded just a few days ago.
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
...
public AuthenticationProviderType GetAuthenticationProviderType(Uri address)
{
IServiceManagement<IOrganizationService> organizationServiceManagement
= ServiceConfigurationFactory.CreateManagement
<IOrganizationService>(address);
return organizationServiceManagement.AuthenticationType;
}
Assuming that you're aiming for AD, you're in luck. It's the easiest.
Uri organizationUrl = new Uri("http ... Organization.svc");
OrganizationServiceProxy organizationService = new OrganizationServiceProxy(
organizationUrl, null, null, null);
If you're aiming for Live Id - that's stingy. I'm still trying to set up a graspable example. The ones at MSDN are just too heavy and confusing. At least when one's dense and lazy like me. More info at mentioned but undisclosed location.

Resources