I need to use same entity DatabaseContext constructor for different connections (between sqlite and mysql). The connection string can changes (for both connections), so i can't use definied connectionString in App.config (or I need to change it somehow).
Two DatabaseContexts
UPDATE:
Here's code from pic above where I use different entity DatabaseContext constructors. In comment of first constructor shown unworking code how I want to use it (different database connections in same constructor).
/// <summary>
/// Sqlite database connection
/// </summary>
/// <param name="connectionString"></param>
public DatabaseContext(string connectionString) : base(new SQLiteConnection() {ConnectionString = connectionString}, true)
{
//base.Configuration = new MySqlConnection();
//base.Configuration = new SQLiteConnection() {ConnectionString = connectionString}, true);
}
/// <summary>
/// MySql database connection
/// </summary>
/// <param name="connectionString"></param>
/// <param name="mock">Identifies mysql connect</param>
public DatabaseContext(string connectionString, bool mock) : base(new MySqlConnection() {ConnectionString = connectionString}, true)
{
}
Related
We have 3 cleints namely- TestingClient, ITestingClient and ITestingClientExtension. Ideally we would like to assign a variable in our winform. In order to assign the variable we declared
TestingClient client = new TestingClient(new Uri("https://rserver.contoso.com:12800")); We get an error stating delegation handler is protected. How do we establish this connection. Thank you
TestingClient.cs begins with this:
{
/// <summary>
/// The base URI of the service.
/// </summary>
public Uri BaseUri { get; set; }
/// <summary>
/// Gets or sets json serialization settings.
/// </summary>
public JsonSerializerSettings SerializationSettings { get; private set; }
/// <summary>
/// Gets or sets json deserialization settings.
/// </summary>
public JsonSerializerSettings DeserializationSettings { get; private set; }
/// <summary>
/// Subscription credentials which uniquely identify client subscription.
/// </summary>
public ServiceClientCredentials Credentials { get; private set; }
/// <summary>
/// Initializes a new instance of the TestingClient class.
/// </summary>
/// <param name='handlers'>
/// Optional. The delegating handlers to add to the http client pipeline.
/// </param>
protected TestingClient(params DelegatingHandler[] handlers) : base(handlers)
{
this.Initialize();
}
/// <summary>
/// Initializes a new instance of the TestingClient class.
/// </summary>
/// <param name='rootHandler'>
/// Optional. The http client handler used to handle http transport.
/// </param>
/// <param name='handlers'>
/// Optional. The delegating handlers to add to the http client pipeline.
/// </param>
protected TestingClient(HttpClientHandler rootHandler,params DelegatingHandler[]handlers):base(rootHandler,handlers)
{
this.Initialize();
}```
In a nutshell, you should use one of the public constructors rather than your current attempt to use one of the protected ones. Here's a screenshot (with public constructors in yellow) from a recent client I generated for that APIs, in the same way yours was generated ("Add REST Client").
For example, your code will need to look more like
Uri u = new Uri("https://rserver.contoso.com:12800")
ServiceCredential sc = ...create a relevant credential...
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fill it in
TestingClient client = new TestingClient(u, sc);
In my Web api project I am having a controller DocumentViewerV1Controller which has a code as:
/// <summary>
///
/// </summary>
/// <param name="documentViewerService"></param>
public DocumentViewerV1Controller(IDocumentViewerService<HtmlViewInformation> documentViewerService)
{
_documentViewerHtmlService = documentViewerService;
}
/// <summary>
///
/// </summary>
/// <param name="documentViewerService"></param>
public DocumentViewerV1Controller(IDocumentViewerService<PageImage> documentViewerService)
{
_documentViewerImageService = documentViewerService;
}/// <summary>
/// Rendering Document as Html
/// </summary>
/// <returns></returns>
[HttpGet]
[Route(WebApiConfig.RootApiUri + "/v1/viewashtml/{docid}")]
public string ViewAsHtml(string docId)
{
var documentInfo = new DocumentInfo { DocumentName = HostingEnvironment.MapPath("~/Uploads/") + docId };
var response = _documentViewerHtmlService.RenderDocument(documentInfo, DocumentRenderType.Html);
return GenerateResponse(response);
}
When I run my service, make a call and debug the constructor initialization, It doesn't goes through the initialization which makes _documentViewerHtmlService as null, eventually fails returning Null reference Exception.
Is it possible to have service Interface as IDocumentViewerService?
Yes, but you'll need to remove one of the constructors or tell it which one to use.
container.RegisterType<IViewerInformation, HtmlViewerInformation>();
container.RegisterType<IDocumentViewerService<IViewerInformation>, DocumentViewerServce<IViewerInformation>>();
You may / may not also need to initialize some of the constructors which you can do by
container.RegisterType<IDocumentViewerService<IViewerInformation>, DocumentViewerServce<IViewerInformation>>(
new InjectionConstructor(...));
While trying to implement EF Migrations in my project I am stuck at one place.
EF Code First MigrateDatabaseToLatestVersion accepts connection string Name from config.
In my case database name get known at Runtime (User selects it from dropdown).
Just the way DbContext either accepts, ConnectionString or connectionString Name in it's constructor, "MigrateDatabaseToLatestVersion" does not accept the same
System.Data.Entity.Database.SetInitializer
(new MigrateDatabaseToLatestVersion<SrcDbContext, SRC.DomainModel.ORMapping.Migrations.Configuration>(connString));
Is there any other way to achieve this?
Thank you all. I did checkout the EF code from codeplex, and inherited my own class after understanding their source code. Here is the solution which I opted :-
public class MigrateDbToLatestInitializerConnString<TContext, TMigrationsConfiguration> : IDatabaseInitializer<TContext>
where TContext : DbContext
where TMigrationsConfiguration : DbMigrationsConfiguration<TContext>, new()
{
private readonly DbMigrationsConfiguration config;
/// <summary>
/// Initializes a new instance of the MigrateDatabaseToLatestVersion class.
/// </summary>
public MigrateDbToLatestInitializerConnString()
{
config = new TMigrationsConfiguration();
}
/// <summary>
/// Initializes a new instance of the MigrateDatabaseToLatestVersion class that will
/// use a specific connection string from the configuration file to connect to
/// the database to perform the migration.
/// </summary>
/// <param name="connectionString"> connection string to use for migration. </param>
public MigrateDbToLatestInitializerConnString(string connectionString)
{
config = new TMigrationsConfiguration
{
TargetDatabase = new DbConnectionInfo(connectionString, "System.Data.SqlClient")
};
}
public void InitializeDatabase(TContext context)
{
if (context == null)
{
throw new ArgumentException("Context passed to InitializeDatabase can not be null");
}
var migrator = new DbMigrator(config);
migrator.Update();
}
}
public static class DatabaseHelper
{
/// <summary>
/// This method will create data base for given parameters supplied by caller.
/// </summary>
/// <param name="serverName">Name of the server where database has to be created</param>
/// <param name="databaseName">Name of database</param>
/// <param name="userName">SQL user name</param>
/// <param name="password">SQL password</param>
/// <returns>void</returns>
public static bool CreateDb(string serverName, string databaseName, string userName, string password)
{
bool integratedSecurity = !(!string.IsNullOrEmpty(userName) || !string.IsNullOrEmpty(password));
var builder = new System.Data.SqlClient.SqlConnectionStringBuilder
{
DataSource = serverName,
UserID = userName,
Password = password,
InitialCatalog = databaseName,
IntegratedSecurity = integratedSecurity,
};
var db = new SrcDbContext(builder.ConnectionString);
var dbInitializer = new MigrateDbToLatestInitializerConnString<SrcDbContext, SRC.DomainModel.ORMapping.Migrations.Configuration>(builder.ConnectionString);
//following uses strategy to "CreateIfNotExist<>"
dbInitializer.InitializeDatabase(db);
return true;
}
}
You can make the MigrateDatabaseToLatestVersion initializer to use the connection string that was used by the context that triggered the migration in the first place.
This is done by passing useSuppliedContext: true to the MigrateDatabaseToLatestVersion constructor as described in the docs. In your case:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<SrcDbContext, SRC.DomainModel.ORMapping.Migrations.Configuration>(useSuppliedContext: true));
What context is this running under? Website or Desktop App?
Under website, doing that is not a good idea. The database initializing strategy set against the type of context. So different connection strings with same type of context will override each other's init strategy.
If Desktop App, maybe include an extra utility to switch between database?
Either way I don't recommend doing this, but if you really want to do what you mentioned, it looks like you have to hack it.
using (var context = new DbContext("<Your connection string right in here>"))
{
var constructors = typeof (DbMigrator).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
var hackedDbMigrator = constructors[0].Invoke(new object[] { new Configuration(), context }) as DbMigrator;
hackedDbMigrator.Update();
}
The is a issue with Migrations call the DbContext dervied class with parameter. Once this is solved it should work. see here for a sample solution.
EntityFramework code-first custom connection string and migrations
This is my entity class:
public partial class NerdDinnerEntities : ObjectContext
{
public NerdDinnerEntities(string connectionString)
: base(connectionString, "NerdDinnerEntities")
{
try
{
ObjectContext oc = new ObjectContext(connectionString);
oc.Connection.ChangeDatabase("NERDDINNER1");
oc.AcceptAllChanges();
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
catch (Exception ex) { }
}
partial void OnContextCreated();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
public ObjectSet<Dinner> Dinners
{
get
{
if ((_Dinners == null))
{
_Dinners = base.CreateObjectSet<Dinner>("Dinners");
}
return _Dinners;
}
}
private ObjectSet<Dinner> _Dinners;
/// <summary>
/// No Metadata Documentation available.
/// </summary>
public ObjectSet<RSVP> RSVPs
{
get
{
if ((_RSVPs == null))
{
_RSVPs = base.CreateObjectSet<RSVP>("RSVPs");
}
return _RSVPs;
}
}
private ObjectSet<RSVP> _RSVPs;
/// <summary>
/// No Metadata Documentation available.
/// </summary>
public ObjectSet<sysdiagram> sysdiagrams
{
get
{
if ((_sysdiagrams == null))
{
_sysdiagrams = base.CreateObjectSet<sysdiagram>("sysdiagrams");
}
return _sysdiagrams;
}
}
private ObjectSet<sysdiagram> _sysdiagrams;
/// <summary>
/// Deprecated Method for adding a new object to the Dinners EntitySet. Consider using the .Add method of the associated ObjectSet<T> property instead.
/// </summary>
public void AddToDinners(Dinner dinner)
{
base.AddObject("Dinners", dinner);
}
/// <summary>
/// Deprecated Method for adding a new object to the RSVPs EntitySet. Consider using the .Add method of the associated ObjectSet<T> property instead.
/// </summary>
public void AddToRSVPs(RSVP rSVP)
{
base.AddObject("RSVPs", rSVP);
}
/// <summary>
/// Deprecated Method for adding a new object to the sysdiagrams EntitySet. Consider using the .Add method of the associated ObjectSet<T> property instead.
/// </summary>
public void AddTosysdiagrams(sysdiagram sysdiagram)
{
base.AddObject("sysdiagrams", sysdiagram);
}
}
and these is my web.config file as
<add name="NerdDinnerEntities" connectionString="metadata=res://*/Models.NerdDinner.csdl|res://*/Models.NerdDinner.ssdl|res://*/Models.NerdDinner.msl;provider=System.Data.SqlClient;provider connection string="Data Source=#;Database=NERDDINNER;User ID=#;Password=###;MultipleActiveResultSets=True"" providerName="System.Data.EntityClients" />
and i am getting error:
Specified method is not supported
in this line:
oc.Connection.ChangeDatabase("NERDDINNER1");
If you look up the docs at MSDN you will see that the method literally is not supported. It must be a placeholder for future improvements or something.
To expand for those who do want to change the database at runtime:
1.Create an entry in your settings to use in-place of the default in the app.config. Pull out the specifics, like Username, password, catalog name (database name), server etc into other settings entries.
<Setting Name="EntityConnectionString2" Type="System.String" Scope="Application">
<Value Profile="(Default)">metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string="data source={0};initial catalog={1};persist security info=True;user id={2};password={3};encrypt=True;trustservercertificate=True;multipleactiveresultsets=True;App=EntityFramework"</Value>
</Setting>
Please note the {0}..{3} entries & that this connection string is not the whole configuration/connectionStrings/add entry in the app.config
2.Use one of the overloaded constructors for the EF Database that accepts a connection string.
var settings = Properties.Settings.Default;
string constring = string.Format(settings.EntityConnectionString2, settings.Server, settings.Database, settings.User, settings.Password);
NerdDinnerEntities db = new NerdDinnerEntities (constring);
3.To change at runtime you can create a different object in the same manner with a different catalog name, or dispose and recreate the db object with a different catalog name.
ChangeDatabase method of EntityConnection is not supported (http://msdn.microsoft.com/en-us/library/system.data.entityclient.entityconnection.changedatabase.aspx)
If you want to use your data context with another database, create another connection string and create data context instance using new connection string
I've run into a bit of an issue trying to unit test an MVC site I have: I require a lot of the ASP.NET environment to be running (generation of httpcontexts, sessions, cookies, memberships, etc.) to fully test everything.
Even to test some of the less front end stuff needs memberships in order to properly work, and it's been finicky to get this all spoofed by hand.
Is there a way to spin up an application pool inside of NUnit tests? That seems like the easiest way.
If written properly, you shouldn't need to have a real context, real session, cookies, etc. The MVC framework by default provides a HttpContext that can be mocked/stubbed. I'd recommend using a mocking framework like Moq or Rhino Mocks and creating a MockHttpContext class that creates a mock context with all of the properties that you need to test against set up. Here's a mock HttpContext that uses Moq
/// <summary>
/// Mocks an entire HttpContext for use in unit tests
/// </summary>
public class MockHttpContextBase
{
/// <summary>
/// Initializes a new instance of the <see cref="MockHttpContextBase"/> class.
/// </summary>
public MockHttpContextBase() : this(new Mock<Controller>().Object, "~/")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MockHttpContextBase"/> class.
/// </summary>
/// <param name="controller">The controller.</param>
public MockHttpContextBase(Controller controller) : this(controller, "~/")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MockHttpContextBase"/> class.
/// </summary>
/// <param name="url">The URL.</param>
public MockHttpContextBase(string url) : this(new Mock<Controller>().Object, url)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MockHttpContextBase"/> class.
/// </summary>
/// <param name="controller">The controller.</param>
/// <param name="url">The URL.</param>
public MockHttpContextBase(ControllerBase controller, string url)
{
HttpContext = new Mock<HttpContextBase>();
Request = new Mock<HttpRequestBase>();
Response = new Mock<HttpResponseBase>();
Output = new StringBuilder();
HttpContext.Setup(x => x.Request).Returns(Request.Object);
HttpContext.Setup(x => x.Response).Returns(Response.Object);
HttpContext.Setup(x => x.Session).Returns(new FakeSessionState());
Request.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
Request.Setup(x => x.QueryString).Returns(new NameValueCollection());
Request.Setup(x => x.Form).Returns(new NameValueCollection());
Request.Setup(x => x.ApplicationPath).Returns("~/");
Request.Setup(x => x.AppRelativeCurrentExecutionFilePath).Returns(url);
Request.Setup(x => x.PathInfo).Returns(string.Empty);
Response.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
Response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns((string path) => path);
Response.Setup(x => x.Write(It.IsAny<string>())).Callback<string>(s => Output.Append(s));
var requestContext = new RequestContext(HttpContext.Object, new RouteData());
controller.ControllerContext = new ControllerContext(requestContext, controller);
}
/// <summary>
/// Gets the HTTP context.
/// </summary>
/// <value>The HTTP context.</value>
public Mock<HttpContextBase> HttpContext { get; private set; }
/// <summary>
/// Gets the request.
/// </summary>
/// <value>The request.</value>
public Mock<HttpRequestBase> Request { get; private set; }
/// <summary>
/// Gets the response.
/// </summary>
/// <value>The response.</value>
public Mock<HttpResponseBase> Response { get; private set; }
/// <summary>
/// Gets the output.
/// </summary>
/// <value>The output.</value>
public StringBuilder Output { get; private set; }
}
/// <summary>
/// Provides Fake Session for use in unit tests
/// </summary>
public class FakeSessionState : HttpSessionStateBase
{
/// <summary>
/// backing field for the items in session
/// </summary>
private readonly Dictionary<string, object> _items = new Dictionary<string, object>();
/// <summary>
/// Gets or sets the <see cref="System.Object"/> with the specified name.
/// </summary>
/// <param name="name">the key</param>
/// <returns>the value in session</returns>
public override object this[string name]
{
get
{
return _items.ContainsKey(name) ? _items[name] : null;
}
set
{
_items[name] = value;
}
}
}
There's a few things that you could add further like a HTTP Headers collection, but hopefully it demonstrates what you can do.
To use
var controllerToTest = new HomeController();
var context = new MockHttpContextBase(controllerToTest);
// do stuff that you want to test e.g. something goes into session
Assert.IsTrue(context.HttpContext.Session.Count > 0);
With regards to Membership providers or other providers, you've hit on something that can be hard to test. I would abstract the usage of the provider behind an interface such that you can provide a fake for the interface when testing a component that relies on it. You'll still have trouble unit testing the concrete implementation of the interface that uses the provider however but your mileage may vary as to how far you want/have to go with regards to unit testing and code coverage.
I'm not aware of a way to do that since your code isn't in that process and requires a host that isn't in aspnet either. (I've been wrong before though haha)
Theres an older HttpSimulator from Phil Haack, have you given that a whirl?
http://haacked.com/archive/2007/06/19/unit-tests-web-code-without-a-web-server-using-httpsimulator.aspx
You need to build wrapper interfaces for those services. The original MVC2 and MV3 starter project templates did this by default, but for some reason they dropped that in the latest versions.
You can try to find samples of the original AccountController code to give you a starting place. They used IMembershipService and IFormsAuthenticationService
It's relatively straightforward to mock session, context, etc..
Take a look at the MVCContrib project (http://mvccontrib.codeplex.com/) as they have a helper for creating controllers that have all the various contextual objects populated (like HttpContext).