SQL Database access from a WebJob in Azure - azure-sql-database

I plan to use WebJobs as a lightweight substitute for NServiceBus but wanted to first verify that routine SQL Azure Database queries can be made from a triggered WebJob handler? My database access will be through EntityFrameworks.
This SO thread indicates that WebJobs does not support SQL Database but I hope this just means that SQL Database cannot be used as a triggering mechanism for a WebJob handler?
Azure Web Job - How to connect to an Azure MS SQL Database?
I have not found a WebJob sample that issues SQL Database queries but since a WebJob has access to the same app config as the main WebSite I assume database connection details can be made available?

Webjobs are any executable that can run on Azure (so .NET programs will run fine). The triggering mechanism is specific and CANNOT utilize SQL Azure but you can run SQL Azure in your executable code WITHIN the webjob itself.
For Example, this webjob waits for the message 'web-jobs-testing-sql' on 'testwebjobsqueue' before executing the query on the SQL Azure database and writing the results to the text file in the configured storage container:
namespace AzureWebJobs
{
class AzureSqlTest
{
static void Main()
{
JobHost host = new JobHost();
host.RunAndBlock();
}
public static void SyndicateFiles([QueueInput("testwebjobsqueue")] string inputText,
[BlobOutput("temp/WebJobs-log.txt")]TextWriter writer)
{
if (!inputText.StartsWith("web-jobs-testing-"))
return;
writer.WriteLine(String.Format("Starting to do processing for " + inputText + " at {0}", DateTime.Now.ToShortTimeString()));
string storageContainerName = ConfigurationManager.AppSettings["StorageContainerNameTemp"].ToLower();
AzureStorageUtils.ConfigureStorage(storageContainerName);
SQLTest sqlTest = new SQLTest();
sqlTest.RunSqlQuery(inputText, writer);
writer.WriteLine(String.Format("Syndication Finished at {0}", DateTime.Now.ToShortTimeString()));
}
}
class SQLTest
{
public SQLTest()
{
}
public void RunSqlQuery(string queueMessage, TextWriter writer)
{
if (queueMessage == "web-jobs-testing-sql")
{
string connectionString = "Server=tcp:YourDatabaseServerName.database.windows.net,1433;Database=YourDatabaseName;User ID=YourSQLAzureUserID;Password=YourStrongPassword;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;";
SqlConnection sqlConnection1 = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM Users";
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection1;
sqlConnection1.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
// Data is accessible through the DataReader object here.
while (reader.Read())
{
writer.WriteLine(reader.GetValue(1).ToString());
}
reader.Close();
}
sqlConnection1.Close();
}
}
}
}
Of course it would be best to store your connection string, storage container names, etc. in the configuration settings of your website hosting the webjob (you can do this in the 'app settings' and 'connection strings' sections of the 'configure tab' in the azure portal so you don't have any settings in files accessible on the website).

We do not have a triggers for SqlAzure yet. It is something we would consider opening up by way of opening up extensibility for allowing you to Trigger functions based on different events such as SQL Azure, File System watchers etc.
You can share the ConnectionString that you can share between your site and webjob. The following post captures this Use connectionstring in WebJob on Azure

Related

ABP IO Code sample for run multiple databases for multi-tenancy

Please notice that I am talking about ABP.io, not the Boilerplate framework.
The in-build free module Tenant-Management is developed to work with multiple tenants and a unique database. however, the documentation says that the framework has a built-in friendly way to use the multiple database approach, including:
new dbContext
database migration and seeding
Connection String service
I am new in ABP IO, and I want a sample that employs the framework elements to implement a single database for every tenant.
I get started by overriding the tenant create sync method of the tenant management module as follows.
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITenantAppService), typeof(TenantAppService), typeof(ExtendedTenantManagementAppService))]
public class ExtendedTenantManagementAppService : TenantAppService
{
public ExtendedTenantManagementAppService(ITenantRepository tenantRepository,
ITenantManager tenantManager,
IDataSeeder dataSeeder) : base(tenantRepository, tenantManager, dataSeeder)
{
LocalizationResource = typeof(WorkspacesManagerResource);
ObjectMapperContext = typeof(WorkspacesManagerApplicationModule);
}
public override async Task<TenantDto> CreateAsync(TenantCreateDto input)
{
var tenant = await TenantManager.CreateAsync(input.Name);
input.MapExtraPropertiesTo(tenant);
await TenantRepository.InsertAsync(tenant);
await CurrentUnitOfWork.SaveChangesAsync();
using (CurrentTenant.Change(tenant.Id, tenant.Name))
{
//TODO: Handle database creation?
// create database
// migrate
// seed with essential data
await DataSeeder.SeedAsync(
new DataSeedContext(tenant.Id)
.WithProperty("AdminEmail", input.AdminEmailAddress)
.WithProperty("AdminPassword", input.AdminPassword)
);
}
return ObjectMapper.Map<Tenant, TenantDto>(tenant);
}
}
Any code sample?

Connect multiple Databases to .NET core API project via Entity Framework Core

today i'm learning the new ASP.net core API 3.1 and i want to transfert my old websites from MVC4 to web API.
All work good except one thing. The database connection. In my old website, i've a database for each clients (10/15 DB's) and i use main database to get the client databse after connection.
Here is my code for my Old DBContext (for local test here)
public DBContext(string database)
: base("Data Source=***SQLServer***;Initial Catalog=" + database + ";Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False"){}
I get the database name string from the AdminDatabase in the DAL and pass it to DBContext.
But now with the services for connections, i don't understand how to do that. If i place the connection string in appsettings json, i can't pass database name parameter.
I try to specify the connection string directly in the startup.cs file but i've seen somewhere it's not secure to do that, the appsetting.json keep connection strings secret...
If you have idea, let me know friends ;)
For exemple Jhon connect to DB1 because in his company profile the DB
is DB1, and for Jack it's DB2. it's more clear ? and also, i want to
be able to create DB, set the name in company parameter in the
admindatabase and when the user connected, it use the DB set in
admindatabase, and not need to modify the appsettings each time
First, you can store all connection strings in appsetting.json file:
{
"ConnectionStrings": {
"DefaultConnection": "...",
"DB1Connection": " ...",
"DB2Connection": " ..."
//...
}
}
Then ,in the dbcontext, inject HttpContext to get the information of the logged in user, by judging the information of the logged-in user, get correspond connection string name dynamically in OnConfiguring method of DbContext.
public class ApplicationDbContext : IdentityDbContext<IdentityUser>
{
private readonly HttpContext httpContext;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IHttpContextAccessor httpContextAccessor)
: base(options)
{
httpContext = httpContextAccessor.HttpContext;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json")
.Build();
var connectionName = "DefaultConnection";// default connection string
var userName = httpContext.User?.Identity?.Name;
//If you distinguish according to the company you belong to,
//you can also determine to obtain different connection strings by obtaining the company to which the logged-in user belongs
if(userName == "Jhon")
{
connectionName = "DB1Connection";
}
else if (userName == "Jack"){
connectionName = "DB2Connection";
}
optionsBuilder.UseSqlServer(configuration.GetConnectionString(connectionName));
}
}

How to create customize destination(with my own server name, client, username, ect) using JCo3 on Netweaver?

Since Netweaver ship with its own DestinationDataProvider, we can't register our own customized destination data provider. Does means we have to use the Netweaver's destination manager to define a destination and use it in our application? Is there a way to connect to any SAP server and create our own destination without using the Netweaver's destination manager?
The way this is done in JCO 3 is slightly different. The idea is create Properties & place from where it can be retrieved (flat file, ldap etc) and then retrieve the same when you want to connect to a sap server.
// So you First use the following code to create the connection parameters
static String DESTINATION_NAME1 = "ABAP_AS_WITHOUT_POOL";
static String DESTINATION_NAME2 = "ABAP_AS_WITH_POOL";
static
{
Properties connectProperties = new Properties();
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "sap.dsc.com");
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "76");
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "800");
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "dsc007");
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "passwd");
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "en");
createDestinationDataFile(DESTINATION_NAME1, connectProperties);
connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "3");
connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10");
createDestinationDataFile(DESTINATION_NAME2, connectProperties);
}
static void createDestinationDataFile(String destinationName, Properties connectProperties)
{
File destCfg = new File(destinationName+".jcoDestination");
try
{
FileOutputStream fos = new FileOutputStream(destCfg, false);
connectProperties.store(fos, "for tests only !");
fos.close();
}
catch (Exception e)
{
throw new RuntimeException("Unable to create the destination files", e);
}
}
// The following code snippet can then be used elsewhere to connect to the sap server
static String DESTINATION_NAME1 = "ABAP_AS_WITHOUT_POOL";
static String DESTINATION_NAME2 = "ABAP_AS_WITH_POOL";
public static void step1Connect() throws JCoException
{
JCoDestination destination = JCoDestinationManager.getDestination(DESTINATION_NAME1);
System.out.println("Attributes:");
System.out.println(destination.getAttributes());
System.out.println();
}
You have to use NetWeaver's Destination Service. Either create the RFC destinations via the NetWeaver Admin UI or programmatically via the offered APIs for managing the destination configurations.
Nevertheless, you can also create JCoCustomDestination instances based on the JCoDestination instances retrieved from the JCoDestinationManager.

One-Way sync of data without changing schema of source database

I Have a database that we want to partially sync data out of into another database (on Azure).
I have been looking at Sync Framework 2.1 and believe it can solve the problem, however i cannot figure it out from the online documentation.
We have the restraint that we cannot change the schema of the database however we are on SQL 2008 R2 which means that we can use track changes.
I am looking for some advise on how this might be achieved.
currently i have a SyncOrchestrator
var orch = new SyncOrchestrator
{
LocalProvider = new SampleServerSyncProvider(),
RemoteProvider = new SampleClientSymcProvider(),
Direction = SyncDirectionOrder.Upload
};
and then a sync provider
public class SampleServerSyncProvider : DbServerSyncProvider
{
private String SQLLocalConnection = "valid connection string";
public SampleServerSyncProvider()
{
SqlConnection serverConn = new SqlConnection(SQLLocalConnection);
Connection = serverConn;
Connection.Open();
var cmTableSyncAdapter = new SqlSyncAdapterBuilder
{
Connection = serverConn,
ChangeTrackingType = ChangeTrackingType.SqlServerChangeTracking,
SyncDirection = SyncDirection.Bidirectional,
TableName = "my table"
};
SyncAdapters.Add(cmTableSyncAdapter.ToSyncAdapter());
}
}
Currently i am getting an error that talks about initializing the connection. But I cannot find an initialize method on any of the objects
System.InvalidOperationException : Cannot create a SyncAdapter for table 'My table' by using
SqlSyncAdapterBuilder because the connection to the server has not yet
been initialized. Initialize the Connection property of the
SqlSyncAdapterBuilder before you call any of the SqlSyncAdapterBuilder
methods
SQL Change Tracking is only supported on the older offline providers (SqlClientSyncProvider/DbServerSyncProvider/SyncAgent). The newer providers you're trying to use (SqlSyncProvider/SyncOrchestrator) requires a custom change tracking. You cannot mix and match the database sync providers.
have you looked at using SSIS instead?

Changing connection string at runtime for OData/WCF Data Service which uses basic authentication

I have an ODATA services with a single schema. These point to a development database, and is served through a WCF Data Service which is then used by clients running Excel/Powerpivot to fetch their own data for reports and such.
The service is secured at runtime through pretty much the same basic authentication explained here: http://msdn.microsoft.com/en-us/data/gg192997
Now how this needs to work in the live environment is sit on the server and connect to different databases based on the username/password supplied. the Users will be typing in 'username#clientID' and 'password'. 'username#clientID' is then split() and username/password is checked against the SQL database. But the database server URL to check against will be determined by ClientID.
Also, once it is authorized the WCF data service needs to return data from the Database corresponding to the ClientID.
The approach I tried was to modify the connection string in the web.config file, but this doesn't work because it says the file is read-only. I'm not even sure if this would have worked at all. What I need to do is get the EDMX/WCF Data service to return the data from the correct database. Here's what I tried to do:
private static bool TryAuthenticate(string user, string password, out IPrincipal principal)
{
Configuration myWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
myWebConfig.AppSettings.Settings["test"].Value = "Hello";
myWebConfig.Save();
string newConnStr = myWebConfig.ConnectionStrings.ConnectionStrings["IntelCorpEntities"].ToString();
newConnStr.ToString().Replace("SERGEIX01", "SERVERX01");
myWebConfig.ConnectionStrings.ConnectionStrings["IntelCorpEntities"].ConnectionString = newConnStr;
myWebConfig.Save();
if (user.ToLower().Equals("admin") && password.Equals("password"))
{
principal = new GenericPrincipal(new GenericIdentity(user), new string[] { "Users" });
return true;
}
else
{
principal = null;
return false;
}
}
In your DataService derived class override the CreateDataSource method and in it figure out the right connect string, create a new instance of the EF object context for the connection string and return it.
The WCF DS Service will not use the default constructor on the EF object context then, it's completely up to you construct the instance with the right connection string.
In your svc.cs file add following :
protected override NorthWindEntity CreateDataSource()
{
System.Data.EntityClient.EntityConnection connection = new System.Data.EntityClient.EntityConnection();
connection.ConnectionString = "";
NorthWindEntity ctx = new NorthWindEntity(connection);
return ctx;
}