I have a legacy application connected to cloud d365 that uses:
XrmServiceContext : Microsoft.Xrm.Client.CrmOrganizationServiceContext
from Microsoft.Xrm.Client namespace. It was downloaded from there back then. The connetion string looks like this:
"Url=https://org.api.crm4.dynamics.com/XRMServices/2011/Organization.svc;Username=unm;Password=pwd"
is the code affected by WS-Trust deprecation announced by MSFT?
Yes, definitely. You should switch to the following pattern:
targetString = string.Format("AuthType=OAuth;Username={0}; Password={1};Url={2};AppId=51f81489-12ee-4a9e-aaae-a2591f45987d; RedirectUri=app://58145B91-0C36-4500-8554-080854F2AC97;LoginPrompt=Disabled;RequireNewInstance=true", CRMUsername, CRMPassword, CRMAddress);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Note that those are the "default" AppId and RedirectURI and that in production environments you should register your app and use production values.
Related
I have earlier achieved this .net 3.1. But it couldn't be possible with .Net 6 because of startup.cs removed.
I have registered a few services,
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var appSettings = builder.Configuration.GetSection("AppSettings").Get<AppSettings>();
builder.Services.AddScoped<IEncryption, Encryption>();
//Here I need to get the IEncryption Service, and call the method in this service to encrypt/decrypt the connection string to pass to DBContext Service.
builder.Services.AddDbContext<CatalogDbContext>(options => options.UseNpgsql(
appSettings.ConnectionString));
var app = builder.Build();
Earlier in .NET 3.1, I used BuildServicProvider() to get the Encryption service, and call the methods in that service to do the required logic then got the proper connection string I wanted that would be passed to the DBContext service on the next line.
Now, .NET 6/7 is forced to use the services only after app = builder.Build(); so, I can't register the DBCOntext after the build() method.
How can I solve this case? Any recommended approach to do this in .NET 6/7?
You still can useStartup.cs in .net 6
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services); // calling ConfigureServices method
var app = builder.Build();
startup.Configure(app, builder.Environment); // calling Configure method
And then you can use ConfigureServices and Configure methods to register your services before building.
You didn't need to use BuildServiceProvider in .NET Core 3.1 either. AddDbContext has an overload that provides access to an IServiceProvider instance :
builder.Services.AddDbContext<CatalogDbContext>((services,options) =>{
var myOwnDecrypter=services.GetRequiredService<IMyOwnDecrypter>();
var cns=myOwnDecrypter.Decrypt(appSettings.ConnectionString,key);
options.UseNpgsql(cns);
});
or, if you use the ASP.NET Core Data Protection package :
builder.Services.AddDataProtection();
...
builder.Services.AddDbContext<CatalogDbContext>((services,options) =>{
var protector = services.GetDataProtector("Contoso.Example.v2");
var cns=protector.Unprotect(appSettings.ConnectionString);
options.UseNpgsql(cns);
});
or, if IConfiguration.GetConnectionString is used :
builder.Services.AddDataProtection();
...
builder.Services.AddDbContext<CatalogDbContext>((services,options) =>{
var conn_string=services.GetService<IConfiguration>()
.GetConnectionString("MyConnectionString");
var protector = services.GetDataProtector("Contoso.Example.v2");
var cns=protector.Unprotect(conn_string);
options.UseNpgsql(cns);
});
That said, it's the configuration provider's job to decrypt encrypted settings, not the service/context's. ASP.NET Core's configuration allows using multiple different configuration sources in the same host, not just a single settings file. There's nothing special about appsettings.json. That's just the default settings file name.
You can add another settings file with sensitive contents with AddJsonSettings. That file could use the file system's encryption, eg NTFS Encryption, to ensure it's only readable by the web app account
You can read settings from a key management service, like Hashicorp, Azure Key Vault, Amazon Key Management etc.
You can create your own provider that decrypts its input. The answers to this SO questino show how to do this and one of them inherits from JsonConfigurationProvider directly.
Important Caveat: In general, my suggestion below is a bad practice
Do not call BuildServiceProvider
Why is bad? Calling BuildServiceProvider from application code results in more than one copy of singleton services being created which might result in incorrect application behavior.
Justification: I think it is safe to call BuildServiceProvider as long as you haven't registered any singletons before calling it. Admittedly not ideal, but it should work.
You can still callBuildServiceProvider() in .Net6:
builder.Services.AddScoped<IEncryption, Encryption>();
// create service provider
var provider = builder.Services.BuildServiceProvider();
var encryption = scope.ServiceProvider.GetService<IEncryptionService>();
// use service here
or alternatively
builder.Services.AddScoped<IEncryption, Encryption>();
var provider = builder.Services.BuildServiceProvider();
using (var scope = provider.CreateScope()) {
var encryption = scope.ServiceProvider.GetService<IEncryptionService>();
// use service here
}
Alternative:
You can still use the classic startup structure in .Net6/7. We upgraded our .Net3.1 projects to .Net6 without having to rewrite/restructure the Startup()
I have a LUIS application which has multiple versions named, v1, v2, and v3.
v1 is used in Production slot; v2 is used in Staging Slot; v3 is still in development state.
LuisRecognizerOptionsV3 recognizerOptions = new LuisRecognizerOptionsV3(luisApplication)
{
TelemetryClient = telemetryClient,
IncludeAPIResults = true,
PredictionOptions = new Microsoft.Bot.Builder.AI.LuisV3.LuisPredictionOptions()
{
Version = "v3", // Just not seem to work. 404 exception.
IncludeInstanceData = true,
IncludeAllIntents = true,
PreferExternalEntities = true,
}
};
Is it possible to use the luis model version v3 without publishing to any slot?
Is it mandatory to use define both Slot and Version attributes?
I get 404 error incase if I use only version without publishing it to any slot.
Already the endpoints are made public in all versions but still error.
How to overcome these challenges?
Thanks,
pdeepa
Iterative app design for LUIS: https://learn.microsoft.com/en-us/azure/cognitive-services/LUIS/luis-concept-app-iteration
Trained versions aren't automatically available at your LUIS app's endpoint. You must publish or republish a version in order for it to be available at your LUIS app endpoint.
If more versions of the app need to be available at an endpoint, you should export the version and reimport it to a new app. The new app has a different app ID.
Will the application automatically detect which environment that it is in or do you need to tell it?
The API is the same for both client and server side modes. To initialize your application for server side mode, you initialize your TTAPIOptions instance as follows:
// Add your app secret Key here. It looks like: 00000000-0000-0000-0000-000000000000:00000000-0000-0000-0000-000000000000
string appSecretKey = “Your App Key”;
//Set the environment the app needs to run in here
tt_net_sdk.ServiceEnvironment environment = tt_net_sdk.ServiceEnvironment.UatCert;
tt_net_sdk.TTAPIOptions apiConfig = new tt_net_sdk.TTAPIOptions(
tt_net_sdk.TTAPIOptions.SDKMode.Server,
environment,
appSecretKey,
5000);
I want to create a Xamarin.Forms app where I have to login to a specific Azure DevOps environment/project.
To try out the Azure DevOps Service library I first created a Console App (.NET Framework 4.7.2) to login to the Azure DevOps environment/project. The following code was used for login process (+ extra code to validate the connection actualy works).
public void Login(string _userName, string _pwd)
{
ProjectHttpClient projectClient;
this.Credentials = new VssAadCredential(_userName, _pwd);
this.Connection = new VssConnection(new Uri(this.DevOpsPath), this.Credentials);
this.InitReferences(this.ProjectName);
projectClient = this.Connection.GetClient<ProjectHttpClient>();
this.ProjectReference = projectClient.GetProjects(null, top: 1).Result.Where(item => item.Name == this.ProjectName).FirstOrDefault();
}
When I use the same piece of code in the Xamarin.Forms App (.NET Standard 2.1) it no longer works and I get the following error when executing the last line:
One or more errors occurred. (Could not resolve type with token
0100008d from typeref (expected class
'Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContextIntegratedAuthExtensions'
in assembly 'Microsoft.IdentityModel.Clients.ActiveDirectory,
Version=3.19.4.11002, Culture=neutral,
PublicKeyToken=31bf3856ad364e35'))
When using the VssBasicCredential with a personal acces token, the code runs as expected. However I would prefer using the VssAadCredential and not the VssBasicCredential.
I'm not aware that the VssAadCredential is not supported in .NET Standard and can find no documentation relating to the issue.
Has anyone had a similar experience that might solve this problem or can anyone provide me with some documentation declaring that this cannot work as of yet?
I'm testing out deploying my own parse server following the steps in the Parse Server Guide. I've got the server up and running and have been able to create and fetch objects via curl. I built a simple iOS app using the Parse SDK (1.14.2). I've initialized the SDK with the app id and server url as described in the Parse Server Guide. When I try to make requests, I get back unauthorized from the server. Digging further, I noticed that the SDK is not sending the application id header to the server. I modified the SDK to send the application id header and everything works. Am I missing a configuration step somewhere?
This is because you are not passing the ClientKey. In swift 3 you would pass it like this in the didFinishLaunchingWithOptions.
// Init Parse
let configuration = ParseClientConfiguration {
$0.applicationId = PARSE_APP_KEY
$0.clientKey = PARSE_CLIENT_KEY
$0.server = PARSE_SERVER_URL
$0.isLocalDatastoreEnabled = true
}
Parse.initialize(with: configuration)
If you are falling when trying to test CloudCode, then its because your parse-server is not passing the Javascript key. So just make sure you initialize the server to do so if this issue is related to Parse.Cloud function.