Silverlight WCF RIA Services Dynamically Change Connection String - silverlight

We have a Silverlight application which uses WCF RIA Services and Entity Framework 4.1 to connect to a database.
At the moment, the connection string is supplied, as standard within the web.config and this all works successfully.
However, I now want to be able to change the connection string dynamically at runtime based on amongst other things, the user logged in.
I've found some other posts which hint at doing this, but they are using ObjectContext whereas we are using DbContext within the System.Data.Entity namespace and also the DbDomainService class.
In order to compensate for this I have overidden the CreateDbContext() method within my DbDomainService implementation as follows:
protected override CoreContext CreateDbContext()
{
dbServer = null, dbName = null;
httpCookie = System.Web.HttpContext.Current.Request.Cookies["DBServer"];
if (httpCookie != null)
{
dbServer = httpCookie.Value;
}
var cookie = System.Web.HttpContext.Current.Request.Cookies["DBName"];
if (cookie != null)
{
dbName = cookie.Value;
}
if (dbServer == null && dbName == null)
{
return new CoreContext();
}
string connStr = "Data Source=" + dbServer + ";Initial Catalog=" + dbName + ";Integrated Security=true";
return new CoreContext(connStr);
}
This works successfully the first time the Silverlight application is loaded, however, on all subsequent loads, the same connection as established initially is used despite changing the values being substituted into the connection string.
The only way to get the connection to be changed seems to be to recycle the application pool in IIS and load the app again.
Am I doing something wrong? Or is it not possible to have the DbDomainService change it's connection dynamically?

I'm thinking of the instancing model of your domainservice class. Have you tried a custom IDomainServiceFctory ? It permits you to decide when to create a new instance of them and is really simple to implement.
Take also a look at this post by Fredrik Normén.

Related

Correlation Failed, Remote Login. AspNet Core Identity Server

Trying to gain some basic understanding of how this process works as I am receiveing the Correlation failed error. Let me first begin my describing the issue I'm encountering...
QAT is not working properly and is configured as follows:
I have an Identity Server running behind a load balancer for QAT.
All requests sent to the load balancer are https.
The traffic being forwarded to each application server (2 seperate servers in this case) is http.
The Netscaler is adding all necessary X-Forwarded items to the header.
I have another application that also sits behind the load balancer for QAT.
There are 2 seperate servers hosting this application which the netscaler will forward the traffic to.
This application is configured to use the X-Forwarded info from the netscaler.
It is designed to authenticate using the above-mentioned Identity Server.
My issue is that I end up with a never ending loop between the second application and the Identity Server when I deploy to QAT. This is strange to me as my SYS environment works perfectly. My sys environment has a seperate instance of Identity Server and the second Application mentioned (except that there is only a single instance of each application being forwarded to). This also goes through the netscaler and does all the X-Forwarded magic mentioned earlier.
In both situations the setup is identical. The only difference is that QAT has multiple servers hosting each app and SYS only has 1 server hosting each app.
My question is why would this behave differently?
Why would this work in sys but not in qa?
I think at this point we can rule out the callback path, cookie settings, etc... b/c it work in SYS.
Could it be that I need to implement some sore of Data Protection Key middleware in both the identity server and the other applciation? On that note, I really dont understand the Data Protection Keys. Would both the identity server and the seperate application need to store their Keys in the same location (whether that be in the database or filesystem) in order to be able to decrypt the information stored in the cookie...
Any help is greatly appreciated.
It was definitely the Data Protection Keys that were the issue. My solution was simple. Save the encryption key as part of the deployment process, Create an IXmlRepository, and then add that to the startup. Easy Peasy.
using Microsoft.AspNetCore.DataProtection.Repositories;
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
namespace Myapp.Encryption.Repositories
{
public class EncryptionRepository : IXmlRepository
{
private String Key { get; set; }
public EncryptionRepository()
{
var year = Convert.ToString(DateTime.Now.Year + 2);
var key = "<key id=\"983440f7-626b-46e4-8bfa-7c3d6d9d4619\" version=\"1\">" +
" <creationDate>2019-11-13T17:42:58.889085Z</creationDate>" +
" <activationDate>2019-11-13T17:42:58.3843715Z</activationDate>" +
" <expirationDate>" + year + "-02-11T17:42:58.3843715Z</expirationDate>" +
" <descriptor deserializerType=\"Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60\">" +
" <descriptor>" +
" <encryption algorithm=\"AES_256_CBC\" />" +
" <validation algorithm=\"HMACSHA256\" />" +
" <masterKey p4:requiresEncryption=\"true\" xmlns:p4=\"http://schemas.asp.net/2015/03/dataProtection\">" +
" <value>{{Your Encryption Key }}</value>" +
" </masterKey>" +
" </descriptor>" +
" </descriptor>" +
"</key>";
Key = key;
}
public IReadOnlyCollection<XElement> GetAllElements()
{
var collection = new List<XElement>();
collection.Add(XElement.Parse(Key));
return collection;
}
public void StoreElement(XElement element, String friendlyName)
{
// Not required as key is hard coded
}
}
}
services.AddSingleton<IXmlRepository, EncryptionRepository>();
services.AddDataProtection().AddKeyManagementOptions(a => a.XmlRepository = (services.BuildServiceProvider()).GetService<IXmlRepository>());

Using SQL Server Authentication to connect to SSRS from a WinForms Application

I'm busy testing SSRS to see if it's a viable alternative to our current reporting solution. I've set up SSRS on my local machine and have developed a working report using SQL Server Report Builder. Now what I'm trying to do is to call the report from within a WinForms application and display it in a ReportViewer control. The problem is that I've set up SQL Server to use SQL Server Authentication and I'm struggling to figure out how to connect to it programmatically.
The code I've pieced together so far looks like this:
Imports Microsoft.Reporting.WinForms
Public Class frmMain
Public v_report_name As String = "TestReport"
Public v_report_server As String = "http://elnah-ict-dt006:80"
Public v_report_path As String = "/reports_SSRS/"
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'create parameter array
Dim paramlist As New List(Of Microsoft.Reporting.WinForms.ReportParameter)
'create a specific parameter required by the report
Dim param1 As New Microsoft.Reporting.WinForms.ReportParameter("ClientID")
'add values to the parameter here we use a variable that holds the parameter value
param1.Values.Add("0279")
'add parameter to array
paramlist.Add(param1)
'Set the processing mode for the ReportViewer to Remote
ReportViewer1.ProcessingMode = ProcessingMode.Remote
'use the serverreport property of the report viewer to select a report from a remote SSRS server
ReportViewer1.ServerReport.ReportServerUrl = New System.Uri(v_report_server)
ReportViewer1.ServerReport.ReportPath = v_report_path & v_report_name
'select where the report should be generated with the report viewer control or on the report server using the SSRS service.
'Me.ReportViewer1.ProcessingMode = Microsoft.Reporting.WinForms.ProcessingMode.Remote
'add the parameterlist to the viewer
ReportViewer1.ServerReport.SetParameters(paramlist)
Me.ReportViewer1.RefreshReport()
End Sub
End Class
When it hits the SetParameters line towards the bottom, it gets the following error message:
Microsoft.Reporting.WinForms.Internal.Soap.ReportingServices2005.Execution.RSExecutionConnection.MissingEndpointException
HResult=0x80131500
Message=The attempt to connect to the report server failed. Check your connection information and that the report server is a compatible version.
Source=Microsoft.ReportViewer.WinForms
I've tried to find examples of how to set the username and password but from what I can tell, most examples are focused on using Windows Authentication. I've tried the following line but it doesn't work:
ReportViewer1.ServerReport.ReportServerCredentials = New ReportServerCredentials("SA", "mypassword")
I haven't worked in VB.NET for ages so please excuse any obvious errors.
Here's some code from a Web Forms project I was part of the team for recently:
private void SetCredentials()
{
var userName = ConfigurationManager.AppSettings["SSRSUserName"];
var passwordEncrypted = ConfigurationManager.AppSettings["SSRSUserPasswordEncrypted"];
var passwordPlainText = SI.Crypto3.Crypto.Decrypt(passwordEncrypted, PASSPHRASE);
var domain = ConfigurationManager.AppSettings["SSRSUserDomain"];
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(passwordPlainText) && !string.IsNullOrEmpty(domain))
{
this.EventsHubReportViewer.ServerReport.ReportServerCredentials = new ReportServerCredentials(userName, passwordPlainText, domain);
}
}
That's C# but hopefully you can see that the important part is that last line. I think that the equivalent in your case should be:
ReportViewer1.ServerReport.ReportServerCredentials = New ReportServerCredentials(userName, password, domain)
The domain value can be an empty String if your on the same domain as the server.
EDIT:
I looked more closely and the ReportServerCredentials class that code is using is one of our own. In your case, you can use the Microsoft.ReportViewer.WinForms.ReportServerCredentials class, which I don't think has a constructor like that. Looking at the documentation for the NetworkCredentials property of that type indicates that you need to do this:
Dim credentials As New NetworkCredential(userName, password, domain)
ReportViewer1.ServerReport.ReportServerCredentials.NetworkCredentials = credentials

For what design reason is Asp.Net Core SessionKey different than the SessionId?

Some Background
In asp.net core when using SqlServer to store sessions, oddly enough the Id column in the SqlServer table gets set to the value of sessionKey which is a Guid generated by the SessionMiddleware. I say oddly enough because there is a SessionId but the Id in the table isn't set to that, it is set to the SessionKey. (I'm not making this up)
This sessionKey used for the Id in the table is also the value that is encrypted and placed in the session cookie. Here is that SessionMiddleware code:
var guidBytes = new byte[16];
CryptoRandom.GetBytes(guidBytes);
sessionKey = new Guid(guidBytes).ToString();
cookieValue = CookieProtection.Protect(_dataProtector, sessionKey);
var establisher = new SessionEstablisher(context, cookieValue, _options);
tryEstablishSession = establisher.TryEstablishSession;
isNewSessionKey = true;
The SessionId however, is a Guid generated by the DistributedSession object in the following line of code:
_sessionId = new Guid(IdBytes).ToString();
Interestingly the ISession interface provides a property for the SessionId but not the SessionKey. So it's often much easier in code to get access to a SessionId then a SessionKey, for example when you have access to an HttpContext object.
This makes it hard to match up the session to the database record if you desire to do that. This was noted by another user on stackoverflow as well How to Determine Session ID when using SQL Sever session storage.
Why?
What I want to know is why is the system designed this way? Why isn't the SessionId and SessionKey the one and the same? Why use two different Guids? I ask because I'm creating my own implementation of ISession and I'm tempted to use the SessionKey as the SessionId in my implementation so that it's easier to match up a record in the database to a session. Would that be a bad idea? Why wan't DistributedSession object designed that way rather than generating a SessionId that is different than the SessionKey? The only reason I can think of is perhaps trying increase security by obfuscating the linkage between the database record and the session it belongs to. But in general security professionals don't find security through obfuscation effective. So I'm left wondering why such a design was implemented?
I also posted the question on GitHub https://github.com/aspnet/Session/issues/151#issuecomment-287894321 to try to get an answer as well.
#Tratcher answered the question there so I'm pasting his answer below so that it's available here on stackoveflow too.
The lifetimes are different. The true lifetime of a session (and SessionId) is controlled by the server. SessionKey is stored in the cookie and lives on the client for an indeterminate amount of time. If the session expires on the server and then the client sends a new request with the old SessionKey, a new session instance with a new SessionId is created, but stored using the old SessionKey so that we don't have to issue a new cookie.
Put another way, don't depend on things outside of your control. The client can keep and replay their SessionKey indefinitely, but it's the server that decides if that is really still the same session.
In case someone need to get the sessionkey in asp.net core 3
Add DI for IDataProtector (IMPORTANT! when create protector it should be nameof(SessionMiddleware))
public IDataProtector _dataProtector;
public TestController( IDataProtectionProvider dataProtectionProvider )
{
_dataProtector = dataProtectionProvider.CreateProtector(nameof(SessionMiddleware));
}
Create method which will get proper value for the session cookie
private string Pad(string text)
{
var padding = 3 - ((text.Length + 3) % 4);
if (padding == 0)
{
return text;
}
return text + new string('=', padding);
}
Use it
public ActionResult TestSession( )
{
var protectedText = HttpContext.Request.Cookies[ ".AspNetCore.Session" ];
var sessionKey = "";
var protectedData = Convert.FromBase64String(Pad(protectedText));
if (protectedData == null)
{
sessionKey = string.Empty;
}
var userData = _dataProtector.Unprotect(protectedData);
if (userData == null)
{
sessionKey = string.Empty;
}
sessionKey = Encoding.UTF8.GetString(userData);
return Content( sessionKey );
}

Specflow-Share browser session between features if triggered between steps

I have implemented Specflow to reuse some steps across features as in this example -Specflow,Selenium-Share data between different Step definitions or classes .Since, in our project, we are integrating multiple features & reusing them. What is the best way to share browser session across features if its triggered in between steps as per the above approach?
My Scenario:
Once an application created, I need to launch new session, login different User-set different services and approve it.
But after logging in fails with below error on Step definition 4 in reused Whenstep of Given(Set the service to (.*)). That particular step is from different feature, hence the new session needs to be used in those steps. The LaunchURl method below is just launching the website with url, no new session created - This works fine
OpenQA.Selenium.WebDriverException : Unexpected error. System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it "IP here"
[Given(#"A New Application is added")]
public void GivenANewApplicationIsAdded()
{
Given("UK_The Service is set");
Given("User Navigated to New Application screen");
When("User fills up form as in data row 1");
Then("new SID generated");
}
[Given(#"New Browser Launched")]
public void GivenNewBrowserLaunched()
{
SeleniumContext sl = new SeleniumContext();
this.seleniumContext = sl;
}
[Given(#"Login is successful with ""(.*)"" and ""(.*)""")]
public void GivenLoginIsSuccessfulWithAnd(string userName, string password)
{
SuperTests spr = new SuperTests();
_driver = spr.LaunchURL(seleniumContext.WebDriver);
//seleniumContext.WebDriver = _driver;
LoginPage lg = new LoginPage(_driver);
lg.LoginProcess(userName, password);
}
[Given(#"Set the service to ""(.*)""")]
public void GivenSetTheServiceTo(string serviceId)
{
When("Select a Service from the option "+serviceId);
Then("The Services is changed to the one selected " + serviceId);
}
In other feature
[When(#"Select a Service from the option (.*)")]
public void WhenSelectAServiceFromTheOptionTestTeam(string p0)
{
HomePage mst = new HomePage(seleniumContext.WebDriver);
mst.SetServiceId(p0);
}
The 2 work around what we figured was
Create a new instance of binding class to call the methods or steps as shown below
[Given(#"Set the service to ""(.*)""")]
public void GivenSetTheServiceTo(string serviceId)
{
var serIdSteps = new UK_SetServiceIDSteps(seleniumContext);
serIdSteps.WhenUK_SelectAServiceFromTheOptionTest(serviceId);
serIdSteps.ThenUK_TheServicesIsChangedToTheOneSelected(serviceId);
}
or
tried this which worked as well- basically calling a new method to create a new session. for this I need not create any new instance for Binding class. Called the Step directly.
[Given(#"New Browser Launched")]
public void GivenNewBrowserLaunched()
{
SuperTests spr = new SuperTests();
_driver = spr.LaunchURL("Firefox");
seleniumContext.WebDriver = _driver;
}
public void GivenSetTheServiceTo(string serviceId)
{
When("UK_Select a Service from the option "+serviceId);
Then("UK_The Services is changed to the one selected " + serviceId);
}
Not sure, which is correct way of doing it? Trying to figure it out from Reusable steps point?The latter one is not advised as we need to change the type of browser to launch at multiple place.

ORMLite OpenDbConnection gives AccessViolationException

I am using ServiceStack and OrmLite.Oracle. I connect to an old Oracle 7.3 instance using ODBC Driver for Oracle on a Windows Server 2012 x64. ODBC is setup as an ODBC32.
I connect and query the database from my repo like this:
using (IDbConnection db = _context.DbFactory.OpenDbConnection())
{
return db.Select<T>();
}
The _context hold the OrmLiteConnectionFactory which was created like this:
DbFactory= new OrmLiteConnectionFactory(conInfo.ConnectionString,false, ServiceStack.OrmLite.Oracle.OracleDialect.Provider);
My service is running just fine and I can access and query the database, no problem.
But after a certain period of time (30 minutes or so), the connection is lost and I have to restart my service (hosted in a Windows Service) because the call to Open the connection will give me this error: unable to allocate an environment handle.
It might be a normal thing to release the handle to the connection after a while but why it simply doesn't reconnect to it? From OrmLite code, I can see that OpenDbConnection should return a new instance of its connection when the AutoDisposeConnection is set to True or if the internal ormLiteConnection is null. I guess my connection is not null but not quite alive...
private OrmLiteConnection ormLiteConnection;
private OrmLiteConnection OrmLiteConnection
{
get
{
if (ormLiteConnection == null)
{
ormLiteConnection = new OrmLiteConnection(this);
}
return ormLiteConnection;
}
}
public IDbConnection OpenDbConnection()
{
var connection = CreateDbConnection();
connection.Open();
return connection;
}
public IDbConnection CreateDbConnection()
{
if (this.ConnectionString == null)
throw new ArgumentNullException("ConnectionString", "ConnectionString must be set");
var connection = AutoDisposeConnection
? new OrmLiteConnection(this)
: OrmLiteConnection;
return connection;
}
I have tried to set the AutoDisposeConnection to True but when I do, I always get an AccessViolationException saying "Attempted to read or write protected memory. This is often an indication that other memory is corrupt.". What does that mean? Is this an OS, ODBC or OrmLite error? Any idea why this is happening?
I have to say that because I am using Oracle 7.3, I had to recompile the ServiceStack.OrmLite.Oracle.dll so it uses the System.Data.Odbc rather than System.Data.OracleClient (only compatible with v8+).
I really want to avoid to test if the connection is alive or not at every call, so any help to make this work is greatly appreciated. Thanks

Resources