Adding and using Multiple Connectionstrings in .net core - sql-server

I am new to .Net Core - I need to add 2 connectionstrings (One for test db and one for live db), and want to connect to both - i.e. connect to live db and transfer data over to test db. Below is my appsettings.json:
{
"ConnectionStrings": {
"DefaultConnection": "Server=PC\\SQLEXPRESS;Database=[DB];User Id=[Username];Password=[Password];",
"MarkingManagerLIVEConnection": "Server=[IP];Database=[DB];User Id=[Username];Password=[Password]"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
I believe I need to register this:
private static void RegisterDatabase(IServiceCollection services, IConfiguration config)
{
services.AddDbContext<MarkingManagerDbContext>(options => options.UseSqlServer(config.GetConnectionString("DefaultConnection")));
services.AddDbContext<MarkingManagerDbContext>(liveoptions => liveoptions.UseSqlServer(config.GetConnectionString("MarkingManagerLIVEConnection")));
}
This is what is on the console apps Main:
static void Main(string[] args)
{
Console.Write("Register Services");
var services = new ServiceCollection();
RegisterServices.Register(services);
Console.WriteLine("=>Done");
_services = services.BuildServiceProvider();
Console.Write("DB Configuration");
var context = _services.GetRequiredService<MarkingManagerDbContext>();
var mmSeed = _services.GetRequiredService<MarkingManagerSeed>();
if (context.Database.EnsureCreated())
{
context.Database.Migrate();
var mmSeedTesk = mmSeed.Seed();
mmSeedTesk.Wait();
}
Console.WriteLine("=>Done");
Console.WriteLine("Press any key to end the process");
Console.ReadLine();
}
How do I make use of the "Live" Connectionstring ? Or am I missing something?
Thanks for any help!

Related

ABP framework / parallel programming

I have one AsyncPeriodicBackgroundWorkerBase base class(DataValidateWorker) which runs 1 minute interval.
I need to send the data I get from the DB to a third party web service and update the results in the db. A Web service response arrives in about 30-40 seconds. For this reason, I need to send Web service queries simultaneously, not sequentially.
For this reason, I wrote code in accordance with parallel programming as seen below. I cannot pull the database connection for the Task I wrote. DB connection closed, I got many errors like Executing.
How can I create the db connection for my Task?
Would it be better to write this job in an external application (exe or service) instead of ABP?
public class DataValidateWorker : AsyncPeriodicBackgroundWorkerBase
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IDataFilter _dataFilter;
public DataValidateWorker(AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory, IDataFilter dataFilter, IUnitOfWorkManager unitOfWorkManager) : base(timer, serviceScopeFactory)
{
_dataFilter = dataFilter;
_unitOfWorkManager = unitOfWorkManager;
Timer.Period = 60 * 1000; // 60 seconds
}
[UnitOfWork]
protected async override Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
{
try
{
var notificationValidationRepository = workerContext.ServiceProvider.GetRequiredService<IRepository<NotificationValidation, int>>();
var notificationValidationItems = await notificationValidationRepository.GetQueryableAsync();
List<NotificationValidation> list = new List<NotificationValidation>();
using (var uow = _unitOfWorkManager.Begin())
{
using (_dataFilter.Disable<IMultiTenant>())
{
list = notificationValidationItems.Where(x => x.RecordDateTime <= DateTime.Now && x.ValidationResult == (int)ValidationResult.NotStarted).ToList();
}
}
NotificationValidationArgs jobArgs = new NotificationValidationArgs();
foreach (var item in list)
{
jobArgs.notificationValidationId = item.Id;
Task taskA = Task.Factory.StartNew(async (Object obj) =>
{
// doing some third party web service operations and db operations
}, jobArgs);
}
}
catch (Exception ex)
{
Logger.LogCritical(2001, ex, DateTime.Now.ToString() + " -> DataValidateWorker -> try 1 -> RDMS uow");
}
}
}
You don't await any of tasks, so lifetime of object ends while your task is still running.
Try to store all of the tasks in a collection and await them before method execution finishes.
Something like below:
public class DataValidateWorker : AsyncPeriodicBackgroundWorkerBase
{
public DataValidateWorker(AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory) : base(timer, serviceScopeFactory)
{
}
protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
{
var tasks = new List<Task>();
foreach (var item in list)
{
tasks.Add(YourLongJob(arg)); // don't await here. collect in a collection
}
await Task.WhenAll(tasks); // wait until all of them is completed.
}
private async Task YourLongJob(object arg)
{
await Task.Delay(30 * 1000); // a long job
}
}

What should I do to be able to test a custom translated function in Sqlite in-memory database?

In my team's project, we use sql-server as database and sqlite as integration test's database.
I really want to use DayOfWeek to group things.
So I created a translation In DBContext class like so
...
public int? DayOfWeek(DateTimeOffset date) => throw new Exception();
...
protected override void OnModelCreating(ModelBuilder builder)
{
var DayOfWeekMethodInfo = typeof(DBContext).GetMethod(nameof(DBContext.DayOfWeek));
if (Database.IsSqlServer())
{
builder
.HasDbFunction(DayOfWeekMethodInfo)
.HasTranslation(args => SqlFunctionExpression.Create("DATEPART", new[]
{
new SqlFragmentExpression("weekday"),
args.ToArray()[0]
}, typeof(int?), null));
else
{
builder
.HasDbFunction(DayOfWeekMethodInfo)
.HasTranslation(args => SqlFunctionExpression.Create("strftime", new[]
{
new SqlFragmentExpression("'%w'"),
args.ToArray()[0]
}, typeof(int?), null));
}
}
In use:
public IQueryable<TransactionCount> SomeRandomFunction()
{
return from t in QueryAllTransaction()
group t by new
{
dayOfWeek = dbConText.DayOfWeek(t.transactionDate)
}
into g
select new TransactionCount
{
dayOfWeek = g.Key.dayOfWeek,
count = g.Count()
};
}
When debuging (sql-server), the code is working fine. But in the test, it thrown error
System.InvalidOperationException : The LINQ expression
'DbSet could not be translated. Either rewrite the query
in a form that can be translated, or switch to client evaluation
explicitly by inserting a call to either AsEnumerable(),
AsAsyncEnumerable(), ToList(), or ToListAsync().
What should I do to be able to test the function in Sqlite in-memory database?

Multiple certificates for Issuer ITfoxtec.Identity.Saml2

As context: I am trying to implement SAML2.0 authentication using ITfoxtec.Identity.Saml2 library. I want to use multiple certificates for one Service Provider, because different clients could login to Service Provider and each of them can have its own certificate. I need a third-party login service have possibility to choose among the list of certificates from my Service Provider metadata.xml when SAML request happened. Does ITfoxtec.Identity.Saml2 library support this possibility or are there some workarounds how it can be implemented?. Thank You
You would normally have one Saml2Configuration. But in your case I would implement some Saml2Configuration logic, where I can ask for a specific Saml2Configuration with the current certificate (SigningCertificate/DecryptionCertificate). This specific Saml2Configuration is then used in the AuthController.
The metadata (MetadataController) would then call the Saml2Configuration logic to get a list of all the certificates.
Something like this:
public class MetadataController : Controller
{
private readonly Saml2Configuration config;
private readonly Saml2ConfigurationLogic saml2ConfigurationLogic;
public MetadataController(IOptions<Saml2Configuration> configAccessor, Saml2ConfigurationLogic saml2ConfigurationLogic)
{
config = configAccessor.Value;
this.saml2ConfigurationLogic = saml2ConfigurationLogic;
}
public IActionResult Index()
{
var defaultSite = new Uri($"{Request.Scheme}://{Request.Host.ToUriComponent()}/");
var entityDescriptor = new EntityDescriptor(config);
entityDescriptor.ValidUntil = 365;
entityDescriptor.SPSsoDescriptor = new SPSsoDescriptor
{
WantAssertionsSigned = true,
SigningCertificates = saml2ConfigurationLogic.GetAllSigningCertificates(),
//EncryptionCertificates = saml2ConfigurationLogic.GetAllEncryptionCertificates(),
SingleLogoutServices = new SingleLogoutService[]
{
new SingleLogoutService { Binding = ProtocolBindings.HttpPost, Location = new Uri(defaultSite, "Auth/SingleLogout"), ResponseLocation = new Uri(defaultSite, "Auth/LoggedOut") }
},
NameIDFormats = new Uri[] { NameIdentifierFormats.X509SubjectName },
AssertionConsumerServices = new AssertionConsumerService[]
{
new AssertionConsumerService { Binding = ProtocolBindings.HttpPost, Location = new Uri(defaultSite, "Auth/AssertionConsumerService") }
},
AttributeConsumingServices = new AttributeConsumingService[]
{
new AttributeConsumingService { ServiceName = new ServiceName("Some SP", "en"), RequestedAttributes = CreateRequestedAttributes() }
},
};
entityDescriptor.ContactPerson = new ContactPerson(ContactTypes.Administrative)
{
Company = "Some Company",
GivenName = "Some Given Name",
SurName = "Some Sur Name",
EmailAddress = "some#some-domain.com",
TelephoneNumber = "11111111",
};
return new Saml2Metadata(entityDescriptor).CreateMetadata().ToActionResult();
}
private IEnumerable<RequestedAttribute> CreateRequestedAttributes()
{
yield return new RequestedAttribute("urn:oid:2.5.4.4");
yield return new RequestedAttribute("urn:oid:2.5.4.3", false);
}
}

node-mssql - Connection is closed

I use node typescript with mssql library to insert data into tables in my Azure server. I create a global connection pool, init it in the constructor then connect to it from route service. However, it shows the error
ConnectionError: Connection is closed at ActionService.insertion", "...at new ActionService", "... at new AppDataServices".
I don't know where broke down my logical connection between the global pool and route service. My SQL query might be wrong, but the main thing is about connection to the database.
Below is my code:
app-data-services.ts (global connection pool):
import * as mssql from 'mssql';
import { AppConfig } from '../config';
import { ActionService } from './data-services';
import { Logger, LoggerFactory } from '../common';
export class AppDataServices {
private static readonly LOGGER: Logger = LoggerFactory.getLogger();
private db: any;
public actionService: ActionService;
constructor(private appConfig: AppConfig) {
this.initConnectionPool();
this.actionService = new ActionService(this.db, AppDataServices.LOGGER);
}
private initConnectionPool() {
this.db = new mssql.ConnectionPool({
user: this.appConfig.mssqlUsername,
password: this.appConfig.mssqlPassword,
server: this.appConfig.mssqlServer,
database: this.appConfig.mssqlDatabase,
// If you are on Microsoft Azure, you need this:
options: { encrypt: true }
}, (err: any) => {
if (err) AppDataServices.LOGGER.error('MSSQL error', err);
});
}
}
action-service.ts (route data service):
import * as mssql from 'mssql';
import { Logger, LoggerFactory } from '../../../common';
export class ActionService {
private static readonly LOGGER: Logger = LoggerFactory.getLogger();
constructor (private db: any, private logger: any) {
this.insertion();
}
insertion() {
const request = new mssql.Request(this.db);
request.query(
`
INSERT INTO dbo.action
(timestamp, result, description, request_endpoint, request_payload, response_status, response_payload, actualAmount, rule_id, lendbook_id)
SELECT t1.start, 'SUCCESS', NULL, '/lendbook/usd', NULL, '200', NULL, t1.originalAmount, t1.id, t2.id
FROM dbo.rule t1, dbo.lendbook t2
INNER JOIN t2.id = t1.id
`, (err, result) => {
if (err) {
console.error(err);
return;
}
return result.recordsets[0];
});
}
}

How can I access sqlite database on a webserver in codename one

Pls How can I access sqlite database on the webserver in codename one? I can only use database API to access database on the device. In order to access this on the webserver I think is quite different thing. Pls I need a snippet code on this. Thanks
Use the code below, not tested and you may have to adjust it to suite your need. Leave a comment if there's an issue:
ConnectionRequest req = new ConnectionRequest() {
#Override
protected void handleException(Exception ex) {
//handle error
}
};
req.setUrl(YourURL);
req.setPost(true);
req.setHttpMethod("POST"); //Change to GET if necessary
req.setDuplicateSupported(true);
req.addArgument("argumentToSendThroughPostOrGet1", "value1");
req.addArgument("argumentToSendThroughPostOrGet2", "value2");
NetworkManager.getInstance().addToQueueAndWait(req);
if (req.getResponseCode() == 200) {
Map<String, Object> out = new HashMap<>();
Display.getInstance().invokeAndBlock(() -> {
JSONParser p = new JSONParser();
try (InputStreamReader r = new InputStreamReader(new ByteArrayInputStream(req.getResponseData()))) {
out.putAll(p.parseJSON(r));
} catch (IOException ex) {
//handle error
}
});
if (!out.isEmpty()) {
List<Map<String, Object>> responses = (List<Map<String, Object>>) out.get("response");
for (Object response : responses) {
Map res = (Map) response;
System.out.println(res.get("key"));
}
} else {
//handle error
}
} else {
//handle error
}
TEST JSON RESPONSE:
{
"response": [
{
"key": "I was returned",
}
]
}
EDIT:
To pass data from TextField:
req.addArgument("argumentToSendThroughPostOrGet1", myTextField.getText());
Based on your comment, you can read those arguments in PHP as simple as below:
$var1 = $_POST["argumentToSendThroughPostOrGet1"];
$var1 = $_GET["argumentToSendThroughPostOrGet1"]; // if GET method is used in Codename One
//Or use $_REQUEST which supports both methods but not advisable to be used for production
...
And you can use those variables in your php code normally.
Example of Usage with MySql Query:
class Connection {
function connect() {
$mysqli = mysqli_init();
$mysqli->real_connect("localhost", "username", "password", "databaseName") or die('Could not connect to database!');
$mysqli->query("SET NAMES 'UTF8'");
return $mysqli;
}
function close() {
mysqli_close($this->connect);
}
}
$connection = new Connection();
$mysqli = $connection->connect();
$mysqli->query("SELECT * FROM MyTable WHERE ColumnName LIKE '%$var1%' ORDER BY PrimaryKeyId ASC LIMIT 100");

Resources