invalid value for key attachdbfilename mvc 4 - asp.net-mvc-4

I'm doing a very basic MVC 4 project. I have a simple model and a dbcontext. I am trying to take input from a form and save it using the dbcontext.
Here's my codes,
In the controller
public ActionResult FormShow(Models.bullseye sampbe)
{
if (ModelState.IsValid)
{
var db = new bullseyeDataContext();
db.bullseyes.Add(sampbe);
db.SaveChanges();
return RedirectToAction("FormShow");
}
return FormShow();
}
In the dbcontext
public class bullseyeDataContext : DbContext
{
public DbSet<bullseye> bullseyes { get; set; }
static bullseyeDataContext()
{
Database.SetInitializer(new DropCreateDatabaseAlways<bullseyeDataContext>());
}
}
And the connectionstring is
<add name="MvcFourFirstTouch.Models.bullseyeDataContext"
connectionString="Data Source=(LocalDb)\v11.0;
Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\MvcFourFirstTouch.Models.bullseyeDataContext.mdf" providerName="System.Data.SqlClient" />
And when i submit the form i'm getting invalid value for key attachdbfilename. Where's the problem??

Updated
The problem is with your connection string. AttachDBFileName does not like the value you've specified to it. Could be an issue with the db name, or an issue with LocalDB, or the lack/presence of an extra \ in the paths.
However, if you have no explicit reason for using AttachDBFileName, then I would suggest replacing AttachDbFileName=[...].mdf with Initial Catalog=yourDBName. You avoid a lot if issues this way :)

Related

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));
}
}

Unable to access data in an ASP.NET MVC web application using Entity Framework and SQL Server database

In an ASP.NET MVC web application, I have created the following entity:
[Table("tblEmployee")]
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
}
But, when I try to retrieve data from a database table called tblEmployee using Entity Framework, I get an error. What I have done until now is:
Created a database MVCDemo with "." as server name and using Windows authentication containing a table called tblEmployee
Installed Entity Framework
Added EmployeeContext.cs class file to Models folder
Code:
namespace MVCDemo.Models
{
public class EmployeeContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
}
}
Added a connection string to web.config file in the root directory
<connectionSrtings>
<add name="EmployeeContext"
connectionString="server=.; database=MVCDemo; integrated security=SSPI"
providerName="System.Data.SqlClient;" />
</connectionSrtings>
Added Details actionResult to EmployeeController to show employee details:
namespace MVCDemo.Controllers
{
public class EmployeeController : Controller
{
// GET: Employee
public ActionResult Details(int id)
{
EmployeeContext employeeContext = new EmployeeContext();
Employee employee = employeeContext.Employees.Single(e => e.EmployeeId == id);
return View(employee);
}
}
}
Finally, I added the following code to Global.asax to prevent initialization:
Database.SetInitializer<MVCDemo.Models.EmployeeContext>(null);
The problem is when I run the application I get this error:
HTTP Error 500.19 - Internal Server Error
The requested page cannot be accessed because the related configuration data for the page is invalid.
and when I comment connection strings out and try to reach
http://localhost:60613/Employee/Details/1
to show details of 1st employee, I get this error:
System.Data.Entity.Core.EntityException: 'The underlying provider failed on Open.'SqlException: Cannot attach the file 'C:\Users\arya\source\repos\MVCDemo\MVCDemo\App_Data\MVCDemo.Models.EmployeeContext.mdf' as database 'MVCDemo.Models.EmployeeContext'.
Check your tag name, it is incorrect. It will trigger the error definitely.
<connectionSrtings>
It should be:
<connectionStrings>
Update:
Since you have another issue, fix the last part of your connection string:
providerName="System.Data.SqlClient;
Remove the semi-colon at the end of SqlClient.
This is because if you have the database named MVCDemo in the SQL Server then its fine, otherwise code first approach looking for MVCDemo database in SQL Server. If you dont have the database in SQL Server, then try this connection string to create the mdf file first.
connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-MVCDemo-20200820010246.mdf;Initial Catalog=aspnet-MVCDemo-20200820010246;Integrated Security=True"
First of all, I couldn't see your database connection. Yes you have teached the table but you didn't tell the program where to put those infos. Something like:
optionsBuilder.UseSqlServer("Data Source=databaseName")
Second possible reason is your program don't know where to go at the beginning. I had those error before and solved it with using default map.
Third reason, this probably not true but, you wrote "connectionSrtings" wrong. As I say, it's probably not that but I wanted to mention if it is.

Save complex object to session ASP .NET CORE 2.0

I am quite new to ASP .NET core, so please help. I would like to avoid database round trip for ASP .NET core application. I have functionality to dynamically add columns in datagrid. Columns settings (visibility, enable, width, caption) are stored in DB.
So I would like to store List<,PersonColumns> on server only for actual session. But I am not able to do this. I already use JsonConvert methods to serialize and deserialize objects to/from session. This works for List<,Int32> or objects with simple properties, but not for complex object with nested properties.
My object I want to store to session looks like this:
[Serializable]
public class PersonColumns
{
public Int64 PersonId { get; set; }
List<ViewPersonColumns> PersonCols { get; set; }
public PersonColumns(Int64 personId)
{
this.PersonId = personId;
}
public void LoadPersonColumns(dbContext dbContext)
{
LoadPersonColumns(dbContext, null);
}
public void LoadPersonColumns(dbContext dbContext, string code)
{
PersonCols = ViewPersonColumns.GetPersonColumns(dbContext, code, PersonId);
}
public static List<ViewPersonColumns> GetFormViewColumns(SatisDbContext dbContext, string code, Int64 formId, string viewName, Int64 personId)
{
var columns = ViewPersonColumns.GetPersonColumns(dbContext, code, personId);
return columns.Where(p => p.FormId == formId && p.ObjectName == viewName).ToList();
}
}
I would like to ask also if my approach is not bad to save the list of 600 records to session? Is it better to access DB and load columns each time user wants to display the grid?
Any advice appreciated
Thanks
EDIT: I have tested to store in session List<,ViewPersonColumns> and it is correctly saved. When I save object where the List<,ViewPersonColumns> is property, then only built-in types are saved, List property is null.
The object I want to save in session
[Serializable]
public class UserManagement
{
public String PersonUserName { get; set; }
public Int64 PersonId { get; set; }
public List<ViewPersonColumns> PersonColumns { get; set; } //not saved to session??
public UserManagement() { }
public UserManagement(DbContext dbContext, string userName)
{
var person = dbContext.Person.Single(p => p.UserName == userName);
PersonUserName = person.UserName;
PersonId = person.Id;
}
/*public void PrepareUserData(DbContext dbContext)
{
LoadPersonColumns(dbContext);
}*/
public void LoadPersonColumns(DbContext dbContext)
{
LoadPersonColumns(dbContext, null);
}
public void LoadPersonColumns(DbContext dbContext, string code)
{
PersonColumns = ViewPersonColumns.GetPersonColumns(dbContext, code, PersonId);
}
public List<ViewPersonColumns> GetFormViewColumns(Int64 formId, string viewName)
{
if (PersonColumns == null)
return null;
return PersonColumns.Where(p => p.FormId == formId && p.ObjectName == viewName).ToList();
}
}
Save columns to the session
UserManagement userManagement = new UserManagement(_context, user.UserName);
userManagement.LoadPersonColumns(_context);
HttpContext.Session.SetObject("ActualPersonContext", userManagement);
HttpContext.Session.SetObject("ActualPersonColumns", userManagement.PersonColumns);
Load columns from the session
//userManagement build-in types are set. The PersonColumns is null - not correct
UserManagement userManagement = session.GetObject<UserManagement>("ActualPersonContext");
//The cols is filled from session with 600 records - correct
List<ViewPersonColumns> cols = session.GetObject<List<ViewPersonColumns>>("ActualPersonColumns");
Use list for each column is better than use database.
you can't create and store sessions in .net core like .net framework 4.0
Try Like this
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//services.AddDbContext<GeneralDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc().AddSessionStateTempDataProvider();
services.AddSession();
}
Common/SessionExtensions.cs
sing Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IMAPApplication.Common
{
public static class SessionExtensions
{
public static T GetComplexData<T>(this ISession session, string key)
{
var data = session.GetString(key);
if (data == null)
{
return default(T);
}
return JsonConvert.DeserializeObject<T>(data);
}
public static void SetComplexData(this ISession session, string key, object value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
}
}
Usage
==> Create Session*
public IActionResult Login([FromBody]LoginViewModel model)
{
LoggedUserVM user = GetUserDataById(model.userId);
//Create Session with complex object
HttpContext.Session.SetComplexData("loggerUser", user);
return Json(new { status = result.Status, message = result.Message });
}
==> Get Session data*
public IActionResult Index()
{
//Get Session data
LoggedUserVM loggedUser = HttpContext.Session.GetComplexData<LoggedUserVM>("loggerUser");
}
Hope this is helpful. Good luck.
This is an evergreen post, and even though Microsoft has recommended serialisation to store the object in session - it is not a correct solution unless your object is readonly, I have a blog explaining all scenario here and i have even pointed out the issues in GitHub of Asp.Net Core in issue id 18159
Synopsis of the problems are here:
A. Serialisation isn't same as object, true it will help in distributed server scenario but it comes with a caveat that Microsoft have failed to highlight - that it will work without any unpredictable failures only when the object is meant to be read and not to be written back.
B. If you were looking for a read-write object in the session, everytime you change the object that is read from the session after deserialisation - it needs to be written back to the session again by calling serialisation - and this alone can lead to multiple complexities as you will need to either keep track of the changes - or keep writing back to session after each change in any property. In one request to the server, you will have scenarios where the object is written back multiple times till the response is sent back.
C. For a read-write object in the session, even on a single server it will fail, as the actions of the user can trigger multiple rapid requests to the server and not more than often system will find itself in a situation where the object is being serialised or deserialised by one thread and being edited and then written back by another, the result is you will end up with overwriting the object state by threads - and even locks won't help you much since the object is not a real object but a temporary object created by deserialisation.
D. There are issues with serialising complex objects - it is not just a performance hit, it may even fail in certain scenario - especially if you have deeply nested objects that sometimes refer back to itself.
The synopsis of the solution is here, full implementation along with code is in the blog link:
First implement this as a Cache object, create one item in IMemoryCache for each unique session.
Keep the cache in sliding expiration mode, so that each time it is read it revives the expiry time - thereby keeping the objects in cache as long as the session is active.
Second point alone is not enough, you will need to implement heartbeat technique - triggering the call to session every T minus 1 min or so from the javascript. (This we anyways used to do even to keep the session alive till the user is working on the browser, so it won't be any different
Additional Recommendations
A. Make an object called SessionManager - so that all your code related to session read / write sits in one place.
B. Do not keep very high value for session time out - If you are implementing heartbeat technique, even 3 mins of session time out will be enough.

Entity Connection String Constructor not found in EF 5 and WCF 4.5 at runtime

I have developed web application using VS 2010, WCF 4.0 and EF 4.1.1. My WCF Service developed with multiple EF Connection strings configured in web.config file those are taken from Entity Model app.config file. based on the parameters i am redirecting databases with EF Connection string at runtime.
My WCF4.0 web.config like:
<connectionStrings>
<add name="WMSChennaiDEVEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string="Data Source=192.168.0.89;Initial Catalog=WMSCMSWPROD;User ID=sa;Password=wms#123;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
<add name="WMSHyderabadDEVEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string="Data Source=192.168.0.89;Initial Catalog=WMSHMSWPROD;User ID=sa;Password=wms#123;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
</connectionStrings>
And in my WCF Service.svc.cs file i have written function that has CenterId parameter and based on that ID i am changing my EF Connection strings like this
WMSChennaiDEVEntities EcChennai;
public void SetEntityModel(int CenterId)
{
if (CenterId == 4)
EcChennai = new WMSChennaiDEVEntities(ConfigurationManager.ConnectionStrings["WMSChennaiDEVEntities"].ToString());
else if (CenterId == 10)
EcChennai = new WMSChennaiDEVEntities(ConfigurationManager.ConnectionStrings["WMSHyderabadDEVEntities"].ToString());
}
Now I am going to convert this web application to VS 2012. I have created new EF Model with same entities and created new WCF Service. I have done some changes and everything is working fine when i am using only one EF Connection string.
WMSMainEntities EntCenter = new WMSMainEntities();
public List<WMSCenter> GetCenters()
{
using (var tt = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
EntCenter.Configuration.LazyLoadingEnabled = false;
EntCenter.Configuration.ProxyCreationEnabled = false;
var CenterColl = EntCenter.WMSCenters.ToList();
tt.Complete();
tt.Dispose();
return CenterColl;
}
}
Now I am in big trouble when i am going to change EF Connecction Strings at runtime in the function. Entity is not taking up Connection String parameter as showing message 'does not contain a constructor that takes 1 arguments'
WMSChennaiDEVEntities EcChennai;
public void SetEntityModel(int CenterId)
{
if (CenterId == 4)
EcChennai = new WMSChennaiDEVEntities(ConfigurationManager.ConnectionStrings["WMSChennaiDEVEntities"].ToString());
else if (CenterId == 10)
EcChennai = new WMSChennaiDEVEntities(ConfigurationManager.ConnectionStrings["WMSHyderabadDEVEntities"].ToString());
}
Error msg like:
Error 3 'CTScan.EntityLibrary.WMSChennaiDEVEntities' does not contain a constructor that takes 1 arguments D:\Code\CTScan\CTScan.WCFService\CTScanService.svc.cs 66 29 CTScan.WCFService
I have more than 300 methods already developed in the service. Every function is depend on the SetEntityModel(int CenterId) function.
So please help me to resolve how to call EF5 connection strings in runtime issue.
Thanks in advance.
EDIT:
I have tried by giving connection string directly as follows:
if (CenterId == 4)
{
EcChennai = new WMSHMSWPRODEntities();
string ConStr = "metadata=res://*/CTScanCore.csdl|res://*/CTScanCore.ssdl|res://*/CTScanCore.msl;provider=System.Data.SqlClient;provider connection string='data source=192.168.0.89;initial catalog=WMSHMSWPROD;persist security info=True;user id=sa;password=wms#123;App=EntityFramework'";
EcChennai.Database.Connection.ConnectionString = ConStr;
}
Changes:
1. Removed parameter in connection string 'MultipleActiveResultSets=True;'
2. Removed " and added single quote
3. Error message Keyword not supported: 'metadata'. at EcChennai.Database.Connection.ConnectionString = ConStr;
Keyword not supported: 'metadata'.
Please help me
Add the constructor you are looking for in a partial class outside of the auto-generated entity class:
public partial class WMSChennaiDEVEntities : DbContext
{
public WMSChennaiDEVEntities(string connectionstring)
: base(connectionstring)
{
}
}
This constructor is not included in EF 5 apparently to prevent us from accidentally passing a sql connection string when an entity connection string is desired. Don’t use Code First by mistake

Configuring Fault Contract Exception Handlers in Enterprise Library 6 for WCF

How do you map additional properties of an exception to your custom fault contract when using Enterprise Library 6's Exception Handling Application Block?
This article describes the FaultContractPropertyMapping the same way this one does. If you have a fault contract like so:
[DataContract]
public class SalaryCalculationFault
{
[DataMember]
public Guid FaultID { get; set; }
[DataMember]
public string FaultMessage { get; set; }
}
How do you add another property and map it to the original exception? Lets say I want to show the Stored Procedure name to the client using a new property:
[DataMember]
public string StoredProcedureName { get; set; }
I try editing the mapping shown on page 90 of the "Developer's Guide to Microsoft Enterprise Library-Preview.pdf" which can be found here but it does not seem to work. My new mapping looks like this:
var mappings = new NameValueCollection();
mappings.Add("FaultID", "{Guid}");
mappings.Add("FaultMessage", "{Message}");
mappings.Add("StoredProcedureName", "{Procedure}"); //SqlException has a Procedure property
And here is the policy.
var testPolicy = new List<ExceptionPolicyEntry>
{
{
new ExceptionPolicyEntry(typeof(SqlException),
PostHandlingAction.ThrowNewException,
new IExceptionHandler[]
{
new FaultContractExceptionHandler(typeof(SalaryCalculationFault), mappings)
})
}
};
var policies = new List<ExceptionPolicyDefinition>();
policies.Add(new ExceptionPolicyDefinition(
"TestPolicy", testPolicy));
exManager = new ExceptionManager(policies);
ExceptionPolicy.Reset();
ExceptionPolicy.SetExceptionManager(exManager);
When I do this and catch the FaultException on the client and inspect it, the StoredProcedureName is always empty. Why doesn't it map from the SqlException to the new property in my fault exception?
It turns out you shouldn't actually place the code you expect an exception for inside of the ExceptionManager.Processs() method. I was doing this before:
exManager.Process(() => wimDAL.Execute_NonQueryNoReturn(sc), "TestPolicy");
Insead, just execute the code as normal.
wimDAL.Execute_NonQueryNoReturn(sc);
This does not follow what the "Developer's Guide to Microsoft Enterprise Library-Preview.pdf" says but I guess the documentation is still a work in progress. I hope this helps someone else.