1. Marcos Bolonha
  2. SnapDevelop
  3. Tuesday, 13 April 2021 00:02 AM UTC

Hi,

I'm working on my first .Net DataStore Web Api project and it is really different from PBScript. On DB Server we have many databases (same structure) for different customers (tenants) and I would like to send the database name via HTTP header like:

inv_RESTClient.SetRequestHeader("DbName", "MyDbName")

How can I handle this on Web Api project?

Today I have a appsettings.json:
{
"ConnectionStrings": {
"Test": "Data Source=SRVDB,1433;Initial Catalog=MyDb;Integrated Security=False;User ID=sa;Password=adm;Pooling=True;Min Pool Size=0;Max Pool Size=100;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite"
}
}

and the TestDataContext.cs:

using SnapObjects.Data;
using SnapObjects.Data.SqlServer;

namespace Test
{
public class TestDataContext : SqlServerDataContext
{

public TestDataContext(string connectionString)
: this(new SqlServerDataContextOptions<TestDataContext>(connectionString))
{
}

public TestDataContext(IDataContextOptions<TestDataContext> options)
: base(options)
{
}

public TestDataContext(IDataContextOptions options)
: base(options)
{
}

}
}

and startup.cs:

...

namespace Test
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(m =>
{
m.UseCoreIntegrated();
m.UsePowerBuilderIntegrated(); //add UsePowerBuilderIntegrated
});

// Original AddDataContext
//services.AddDataContext<TestDataContext>(m => m.UseSqlServer(this.Configuration, "Test"));

// Actual AddDataContext

string DbName = "MyDbName"; // ==>> I would like to get de HTTP Request Header "DbName" at this point 

SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(Configuration.GetConnectionString("Test"));
builder.InitialCatalog = DbName;
services.AddDataContext<TestDataContext>(m => m.UseSqlServer(builder.ConnectionString));

...

Thanks.

Marcos

PB 2019 R3 Build 2670

 

Marcos Bolonha Accepted Answer Pending Moderation
  1. Thursday, 15 April 2021 21:49 PM UTC
  2. SnapDevelop
  3. # 1

Hi Appeon team,

 

Any idea how do that? or if is it possible? or any advise the best/other way to do that !

 

Any suggestion will be appreciated.

 

Thanks.

 

Marcos

Comment
  1. Dan Harrel
  2. Friday, 16 April 2021 15:23 PM UTC
I foresee this issue coming up for me as well, and have given it some thought (but no implementation yet). I am also new to all this technology. I'd like to throw out where my thoughts are to see whether they help, and more importantly, how they get corrected!



Armeen - are you suggesting Marcos have a DataContext class for each "tenant", and register each for dependency injection in ConfigureServices(...)? Would each Service class receive the all the DataContext classes by dependency injection in their constructor, and then choose which to use based on an API parameter?



How about forgetting about dependency injecting the database context, and just instantiating it when needed in the Service code, when you know which connection string to pass?



One over-arching comment I would like to make: No-one should underestimate the complexity of adapting to ASP.NET Core and C# by even very experienced PB developers. It is a completely new and much more complex world - especially if you are trying to adhere to best practices developed in that world over many, many years. Myself, I am getting there, but it has been a very difficult journey, and most documentary materials have not made that journey any easier.
  1. Helpful
  1. Francisco Martinez @Appeon
  2. Friday, 16 April 2021 16:53 PM UTC
Hi Dan!

Dependency injection is not a requirement in ASP .NET Core, it's just a code pattern that has a lot of benefits, like swapping out implementations in only one place while affecting every place it's used. There's nothing forbidding you from instantiating the DataContext manually, and while that's one way to do what you want, it will incur in more code, make maintenance harder and if you ever want to change the connection parameters or swap out the implementation altogether, you would need to go to every place you're using that specific DataContext.

Just something to keep in mind.



Regards,

Francisco
  1. Helpful
  1. Dan Harrel
  2. Saturday, 17 April 2021 00:00 AM UTC
Thanks, Francisco. Understood. However if I understand Marcos' requirement properly, he wants the database his Web API connects to to be determined by a Web API parameter. We foresee a similar requirement. If the alternative is to create a DataContext subclass for every possible database he could connect to, and dependency inject each one, then I would rather manually instantiate a DataContext. Maybe there is a sophisticated and concise way of avoiding multiple injection using Generics - I don't know at present. However, I see the manual instantiation to be quite simple: each instantiation retrieves connection parameters from the "appsettings.json" configuration file using a database-selection-specific key. Changing connection parameters is a simple of matter of changing the configuration file entry: one place, one setting. Good PB developers are well versed in strategies to reuse code and avoid duplication - such strategies predate Dependency Injection. This is not to denigrate dependency injection, or dependency inversion, MVC, or all the other state-of-the-art coding patterns that are prevalent in this brave new world of programming. I am finding these to be complex, and frankly, ingenious, solutions that have taken me time to wrap my head around. It is getting easier, however I have a ways to go to achieve fluency. In the meantime, work needs to get done!
  1. Helpful
There are no comments made yet.
Armeen Mazda @Appeon Accepted Answer Pending Moderation
  1. Friday, 16 April 2021 00:56 AM UTC
  2. SnapDevelop
  3. # 2

Hi Marcos,

You need to pre-define multiple DataContext (each with unique name)... one for each database you want to connect to.  Your WebAPI would receive the DataContext name as a parameter, then in C# you would dynamically set the DataContext name to use to do the DB transactions.

Best regards,
Armeen

Comment
  1. Marcos Bolonha
  2. Friday, 16 April 2021 18:02 PM UTC
Hi Armeen,



Thanks for your attention.



I don't know if I correctly understood, but supposing I have new "tenants" every day, I will have to stop the WebApi on IIS then change the codes and re-publish the project every time it occurs. It would be a problem, since other users will be using their application and consuming the APIs.



Best regards.

Marcos
  1. Helpful
  1. Armeen Mazda @Appeon
  2. Saturday, 17 April 2021 03:04 AM UTC
Logan has provided example how to dynamically create.
  1. Helpful
There are no comments made yet.
Logan Liu @Appeon Accepted Answer Pending Moderation
  1. Saturday, 17 April 2021 01:55 AM UTC
  2. SnapDevelop
  3. # 3

 

 

Hi Marcos,

I think an example provided by Juan can help you with this issue.

https://community.appeon.com/index.php/qna/q-a/dynamic-connections-with-snapobjects

It is using  _httpAccessor.HttpContext.Request.Query["connectionID"] to distinguish different tenants, But Request Header, in that example. So you need to modify a few lines of code.

Regards,

Logan

Comment
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.