I have a WCF service hosted in IIS that is retrieving data from multiple sources (all SQL Server). With each data source, I have to impersonate a different Active Directory user to connect to the database. I am using Entity Framework v6.1.1 for two of the data sources. Integrated Security is set to True in the connection strings, too.
I use the example below to set the impersonated user, where the impersonated user is a System.Security.Principal.WindowsImpersonationContext that I set from configuration:
internal async Task<List<string>> GetItemsByLookupItemsAsync(List<string> lookupItems)
{
var result = new List<string>();
using (var db = new EntityFrameworkDb())
{
var query = from item in db.Table
where lookupItems.Contains(item.LookupColumn)
select item.StringColumn;
var queryResult = new List<string>();
using (GetImpersonatedUser())
{
queryResult.AddRange(await query.ToListAsync());
}
result.AddRange(queryResult.OrderBy(e => e));
}
return result;
}
The problem is that the previous code throws a SqlException saying that the account running the web service can not log on to the database. It appears that when I hit the await I lose the impersonation context.
What are some suggestions to solve this problem?
Set the legacyImpersonationPolicy to false and alwaysFlowImpersonationPolicy to true inside your web.config and restart IIS
<configuration>
<runtime>
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
</runtime>
</configuration>
Related
I have a C# .Net Web API deployed to an Azure App Service, I also have an Azure SQL Database.
In the API I am using Entity Framework to insert into the database, but I keep getting the error message: "The underlying provider failed on open".
(When running the API locally (in debug mode) connecting to a local database it works fine).
Could this be a permissions/firewall configuration problem with the Azure database, or something else?
I have added my current IP address in the "Azure Set Server Firewall", do I need to add the Azure Web API's IP address to the database firewall settings?
This is my API:
public class ProfileController : ApiController
{
[EnableCors(origins: "*", headers: "*", methods: "*")]
[WebMethod]
[HttpPost]
public HttpResponseMessage PostProfile([FromBody] Profile details)
{
var context = new XXXDBEntities();
var query = from c in context.Users
where c.Email.Equals(details.email, StringComparison.CurrentCultureIgnoreCase)
select c;
var emailFound = query.Count();
if (emailFound != 0)
{
return Request.CreateResponse(HttpStatusCode.OK, "There is already an account associated with this email address");
}
else
{
Guid token = Guid.NewGuid();
Users newRow = new Users();
newRow.Token = token;
newRow.FirstName = details.firstName;
newRow.LastName = details.lastName;
newRow.Email = details.email;
newRow.Password = details.password;
context.Users.Add(newRow);
context.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK, token);
}
}
This is my connection string:
This is the default format for connection strings in .Net Entity Framework, I have only added username, password and changed the data source and catalog fields. Is this correct?
<add name="XXXDBEntities" connectionString="metadata=res://*/XXXDB.csdl|res://*/XXXDB.ssdl|res://*/XXXDB.msl;provider=System.Data.SqlClient;provider connection string="data source=tcp:XXX.database.windows.net,1433;initial catalog=XXXDB;integrated security=True;User ID=XXXXX;Password=XXXXX;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
I have checked your connection string, it seems to be right. So I think your issue may be caused by the model of the SQL Azure is changed, but your project does not update it. Here is the same issue I reproduced on my side:
I would suggest you update your model.
do I need to add the Azure Web API's IP address to the database firewall settings?
We can set Allow access to Azure services as ON in SQL Azure firewall settings. So that we need not to add Azure web API's address.
You need to remove Integrated Security=True from the connection string since you are specifying a username and password.
I have a web app and a batch pool.
In the batch pool, created tasks are using the same database as the web app.
Today I started receiving the following exception in the batch:
A transport-level error has occurred when receiving results from the server. (provider: Session Provider, error: 19 - Physical connection is not usable)
The code base has not changed, older versions do not work, there were no updates, it just popped out of the blue. I repeated a couple tasks in a controlled debug environment in VS and they went through without any exceptions thrown. I went in and added the batch node’s IP to the sql server firewall rules, also no result. Meanwhile, the web application uses the database just fine.
Both the web app and batch pool are located in East US.
Here’s a snippet from Program.cs in my batch task:
MyEntities db; //MyEntities extends DbContext
System.Data.Entity.Core.EntityClient.EntityConnectionStringBuilder connstr = new System.Data.Entity.Core.EntityClient.EntityConnectionStringBuilder();
connstr.ProviderConnectionString = connectionString;
connstr.Provider = "System.Data.SqlClient";
connstr.Metadata = "res://*/MyEntities.csdl|res://*/MyEntities.ssdl|res://*/MyEntities.msl";
try {
db = new PepeEntities(connstr.ConnectionString);
}
The connection string looks like this:
Persist Security Info=True; Data Source=<host>; Initial Catalog=<database name>; Integrated Security=False; User ID=<login>; Password=<password>; MultipleActiveResultSets=True; Connect Timeout=30; Encrypt=True;
Edit:
This problem has subsided the same way it appeared: out of the blue. I’ll carry out tests whenever it surfaces again.
You can try one of these 2 possibilities:
1. Enabling an Execution Strategy:
public class MyEntitiesConfiguration : DbConfiguration
{
public MyEntitiesConfiguration()
{
SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy());
}
}
# please view more details here:https://msdn.microsoft.com/en-US/data/dn456835
2. if you have explicitly opened the connection, ensure that you close it. You can use an using statement:
using(var db = new PepeEntities(connstr.ConnectionString){
..do your work
}
https://blogs.msdn.microsoft.com/appfabriccat/2010/12/10/sql-azure-and-entity-framework-connection-fault-handling/
I am creating 2 projects that have the same database (it's an MDF database). The first one is the map editor, and I use XNA 4 and Web Services to connect to it. The second one is the game itself and uses XNA 3.1 and Entity Data Model to connect database.
When I run the map editor and access the database, it runs properly. Bbut when I run the game and access the database, it shows an error "The underlying provider failed on Open"
I think the connection from the web service is not closed yet. But I don't know where I should close the connection.
Here is my code from the web service:
public Map AddNewMap(string username, string mapName, int sizeX, int sizeY)
{
using (BaseModelDataContext context = new BaseModelDataContext())
{
Map newMap = new Map()
{
Username = username,
Name = mapName,
SizeX = sizeX,
SizeY = sizeY,
Upload_Date = DateTime.Now,
Status = 0
};
context.Maps.InsertOnSubmit(newMap);
context.SubmitChanges(System.Data.Linq.ConflictMode.FailOnFirstConflict);
context.Dispose();
return newMap;
}
}
EDIT:
Here is the entity data model code :
using (MazeEntities ent = new MazeEntities())
{
ent.Connection.Open();
return (from map in ent.Map
select map).ToList<Map>();
}
This code runs properly if I did not use the web service before. If I use the web service first, it shows an error at ent.Connection.Open();
Here is the inner exception:
Cannot open user default database. Login failed.\r\nLogin failed for user 'erkape-PC\erkape'.
Connection string for web service :
connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\3DMapDatabase.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True"
Connection string for the game:
"metadata=res:///MazeDataModel.csdl|res:///MazeDataModel.ssdl|res://*/MazeDataModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.\SQLEXPRESS;AttachDbFilename=D:\eRKaPe\DropBox\TA\Program\3D_Map_Editor\3DMapEditorServices\App_Data\3DMapDatabase.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
For a quick check, can you try adding the following line after the using:
using (BaseModelDataContext context = new BaseModelDataContext())
{
context.Connection.Open();
OR
context.Database.Connection.Open();
// your code here
Finally I found a way to solve my problem after reading some articles.
The connection from the web service doesn't close automatically after I close the map editor. That is why I can't access my database from the game.
I have to change the connection string from both application, I set the User Instance to False. The game can access the database this way.
Please check the following post
http://th2tran.blogspot.ae/2009/06/underlying-provider-failed-on-open.html
Also please Enable for 32 Bit application in the APplication Pool of that application.
This may resolve.
You are trying to return an object (Map) which is associated with the Context. This object has the context information which can't be returned to the client.
You will need to create your own DataContract (a type having necessary properties) that you want to expose to the client.
Or you can use the POCO implementation As described here
I have an application running on IIS that i'm testing. Everything was fine until i publish it to the server. Server's ip address is 10.0.0.19 (this is a local application). Connection strings etc. everything is properly configured. Every other query in other pages are working fine but in some pages result sets aren't coming from Entity Framework.
Here is a sample code.
List<CCAP.Data.Orm.CustomerField> fieldList = CustomerFieldProvider.GetCustomerFieldList(projectId);
StringBuilder controlsToRender = new StringBuilder();
foreach (var item in fieldList)
{
HtmlTagBuilder tagParaph = new HtmlTagBuilder("p");
HtmlTagBuilder tagLabel = new HtmlTagBuilder("label");
HtmlTagBuilder tagInput = new HtmlTagBuilder("input");
tagInput.AddAttiribute("type","text");
tagInput.AddAttiribute("style", "width :400px;");
tagInput.AddAttiribute("name", item.FieldName);
tagLabel.AddAttiribute("for",item.FieldName);
tagLabel.SetInnerText(item.FieldHeaderText);
tagParaph.AddChildElement(tagLabel);
tagParaph.AddChildElement(tagInput);
controlsToRender.Append(tagParaph.ToString());
}
return controlsToRender.ToString();
What can be wrong about this situation??
The differences when you publish it to IIS are:
Security context
Configuration file
In your case it is probably the security context. Does your connection string use a trusted connection? Does your app pool identity have access to your SQL server.
I have a WCF data service and I am trying to use the UpdateObject method on the DataServiceContext client. When I call the SaveChanges method, I get the following error page:
Unauthorized: Access is denied due to invalid credentials
You do not have permission to view this directory or page using the credentials that you supplied.
Does anyone have any ideas of how I can fix this? I found this, which would theoretically fix the problem, but setting this disk access is not a realistic solution for a production service. Keep in mind, when running this WCF Data service on my local machine, it works just fine. The C# code for my call is below:
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
{
var userName = ( string ) context[ "UserName" ];
var isAuthenticated = ( bool ) context[ "IsAuthenticated" ];
if (userName != null && userName.Length >= 1 && collection.Count >= 1)
{
var allNames = string.Empty;
var allValues = string.Empty;
byte[] buf = null;
PrepareDataForSaving( ref allNames, ref allValues, ref buf, true, collection, isAuthenticated );
if (allNames.Length != 0)
{
var client = GetDataContext( );
var profile = client.ProfileViews.Where(p => p.UserName == userName).FirstOrDefault();
if (profile == null)
{
profile = new ProfileView() { UserName = userName };
client.AddToProfileViews(profile);
}
profile.PropertyNames = allNames;
profile.PropertyValuesString = allValues;
profile.PropertyValuesBinary = buf;
profile.LastUpdateDate = DateTime.UtcNow;
client.UpdateObject(profile);
client.SaveChanges( );
}
}
}
I had a similiar issue with a Silverlight application that was using WCF Data Services. The users could view data in the application---SELECTS from the database were functioning---but they were receiving the same "401 - Unauthorized: Access is denied du to invalid credentials." you are describing when they attempted to save changes to the database (i.e., at the point when SaveChanges was executed in code). The underlying problem ended up being a permissions issue with the IIS application folder itself. To fix, we had to grant the Application Pool being used by the WCF service Write permissions to the folder.
Go to IIS and right click on the virtual directory containing the WCF service and choose Manage Application -> Advanced Settings.... Make note of the Application Pool name.
Within same right-click menu, choose Edit Permissions..... On Security tab, check group and user names.
If the name of the Application Pool is missing. Add it using the name format "IIS APPPOOL\MyApplicationPoolName". See this helpful link: http://www.bluevalleytech.com/techtalk/blog/assigning-ntfs-folder-permission-to-iis7-application-pools/
Make sure MyApplicationPoolName has Write permissions (we actually gave it Full control)
In my case I had Windows authentication with impersonation using kerberos (useAppPoolCredentials=true) on a WCF Data Service hosted on IIS 7.5. The weird thing was that I could successfully select and insert data, but when I tried to update I got a 401.3 access denied error. The solution was to give the AD group specified in the web config (myRole):
<authorization>
<allow roles="myRole"/>
<deny users="*" />
</authorization>
Read and write access to the application folder like Dan Sabin said . The error message was:
Error message 401.3: You do not have permission to view this directory or page using the credentials you supplied (access denied due to Access Control Lists). Ask the Web server's administrator to give you access