How to modify folder permissions in a web setup project? - asp.net

I am using a web setup project to install my ASP.NET app which needs to write to a folder that exists under the main virtual directory folder. How do I configure the setup project to grant the ASPNET user permissions to that folder?

The way to do it is to create a class derived from System.Configuration.Install.Installer. Override the Install() method. The following is an example that changes permissions on a directory and a file, you probably don't want to be so permissive, but it depends on your security context. In order for this to work, the setup project has to run this as a custom action. Add the "Primary Output" from whatever project this class is in. You will also need to pass the directory to the custom action in its properties. The first variable name has to match the code. Like this: /targetdir="[TARGETDIR]\"
[RunInstaller(true)]
public partial class SetPermissions : Installer
{
private const string STR_targetdir = "targetdir";
private const string STR_aspnetUser = "ASPNET";
public SetPermissions()
{
InitializeComponent();
}
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
Context.LogMessage(
Context.Parameters
.Cast<DictionaryEntry>()
.Select(entry => String.Format("String = {0} Value = {1}", entry.Key, entry.Value))
.Aggregate(new StringBuilder("From install\n"), (accumulator, next) => accumulator.AppendLine(next))
.ToString()
);
string targetDir = Context.Parameters[STR_targetdir];
string dbDir = Path.Combine(targetDir, "db");
AddFullControlPermissionToDir(dbDir, STR_aspnetUser);
string rimdbSqliteFilename = Path.Combine(dbDir, "db.sqlite");
AddFullControlPermissionToFile(rimdbSqliteFilename, STR_aspnetUser);
string logsDir = Path.Combine(targetDir, "logs");
AddFullControlPermissionToDir(logsDir, STR_aspnetUser);
}
private static void AddFullControlPermissionToDir(string dir, string user)
{
DirectorySecurity directorySecurity = Directory.GetAccessControl(dir);
directorySecurity.AddAccessRule(
new FileSystemAccessRule(
user,
FileSystemRights.FullControl,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.None,
AccessControlType.Allow));
Directory.SetAccessControl(dir, directorySecurity);
}
private static void AddFullControlPermissionToFile(string filename, string user)
{
FileSecurity fileSecurity = File.GetAccessControl(filename);
fileSecurity.AddAccessRule(
new FileSystemAccessRule(
user,
FileSystemRights.FullControl,
AccessControlType.Allow));
File.SetAccessControl(filename, fileSecurity);
}
}

Related

Issues deploying mvc application that has users and needs an update on the database

I am trying to seed an admin user to my database so that when I deploy, I have one user that can log in....
This is the seed method that I am trying to run, but it gives me "no suitable method found to override". My application user is the stock application user that visual studio gives you in the template.
protected override void Seed(ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
var passwordHash = new PasswordHasher();
string password = passwordHash.HashPassword("Password#123");
context.Users.AddOrUpdate(u => u.UserName,
new ApplicationUser
{
UserName = "Steve#Steve.com",
PasswordHash = password,
PhoneNumber = "08869879"
});
}
Class where you override Seed method need inheriting from DropCreateDatabaseAlways<TContext>.
Error :
no suitable method found to override
Mean only that base class not contains Seed method. You can override it like:
internal sealed class Configuration : DbMigrationsConfiguration<YourContext>
{
protected override void Seed(YourContext context)
{
//add data
}
}

How to reload apache commons configurations2 properties

can anyone guide me on how to perform a reload of an apache commons configuration2 properties. I'm unable to find any implementation of this anywhere. The apache docs are a bit too abstract. This is what I have so far but it's not working.
CombinedConfiguration cc = new CombinedConfiguration();
Parameters params = new Parameters();
File configFile = new File("config.properties");
File emsFile = new File("anotherconfig.properties");
ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> configBuilder =
new ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class)
.configure(params.fileBased()
.setFile(configFile));
PeriodicReloadingTrigger reloadTrg = new PeriodicReloadingTrigger(configBuilder.getReloadingController(), null, 5, TimeUnit.SECONDS);
reloadTrg.start();
cc.addConfiguration(configBuilder.getConfiguration());
FileBasedConfigurationBuilder<FileBasedConfiguration> emsBuilder =
new FileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class)
.configure(params.properties()
.setFile(emsFile));
cc.addConfiguration(emsBuilder.getConfiguration());
DataSource ds = EmsDataSource.getInstance().getDatasource(this);
BasicConfigurationBuilder<DatabaseConfiguration> dbBuilder =
new BasicConfigurationBuilder<DatabaseConfiguration>(DatabaseConfiguration.class);
dbBuilder.configure(
params.database()
.setDataSource(ds)
.setTable("EMS_CONFIG")
.setKeyColumn("KEY")
.setValueColumn("VALUE")
);
cc.addConfiguration(dbBuilder.getConfiguration());
The configuration obtained from a builder is not updated automatically. You need to get the configuration from the builder every time you read it.
From Automatic Reloading of Configuration Sources:
One important point to keep in mind when using this approach to reloading is that reloads are only functional if the builder is used as central component for accessing configuration data. The configuration instance obtained from the builder will not change automagically! So if an application fetches a configuration object from the builder at startup and then uses it throughout its life time, changes on the external configuration file become never visible. The correct approach is to keep a reference to the builder centrally and obtain the configuration from there every time configuration data is needed.
use following code:
#Component
public class ApplicationProperties {
private PropertiesConfiguration configuration;
#PostConstruct
private void init() {
try {
String filePath = PropertiesConstants.PROPERTIES_FILE_PATH;
System.out.println("Loading the properties file: " + filePath);
configuration = new PropertiesConfiguration(filePath);
//Create new FileChangedReloadingStrategy to reload the properties file based on the given time interval
FileChangedReloadingStrategy fileChangedReloadingStrategy = new FileChangedReloadingStrategy();
fileChangedReloadingStrategy.setRefreshDelay(PropertiesConstants.REFRESH_DELAY);
configuration.setReloadingStrategy(fileChangedReloadingStrategy);
} catch (ConfigurationException e) {
e.printStackTrace();
}
}
public String getProperty(String key) {
return (String) configuration.getProperty(key);
}
public void setProperty(String key, Object value) {
configuration.setProperty(key, value);
}
public void save() {
try {
configuration.save();
} catch (ConfigurationException e) {
e.printStackTrace();
}
}
}

Why is the Seed method called again in my EF code first migrations scenario?

I have a EF code first project and there is how I seed the database
internal sealed class Configuration : DbMigrationsConfiguration<myDB>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "myDB.Auth.Service.DAL.myDB";
}
protected override void Seed(myDBdb)
{
var mProduct = new Product
{
Name = "default product",
CreatedDate = DateTime.Now
};
db.Products.AddOrUpdate(mProduct);
db.SaveChanges();
}
}
I have a wcf service that uses above code. What I realise is that every time I restart the wcf service (either from visual studio or IIS), above code is get called. As a result, multiple "default product" are added into the database, anyone knows why that happened?
Migration seed runs after every update-database so you need to make your script idempotent by testing for existance or using AddOrUpdate. If you only want to seed on database creation, there is a separate context seed method that only runs when the database is created.
https://blog.oneunicorn.com/2013/05/28/database-initializer-and-migrations-seed-methods/
AddOrUpdate for seeding
Edit:
When you use MigrateDatabaseToLatestVersion initializer, your seed method runs every time your application runs. If you want to control this process, switch your initializer to null:
Database.SetInitializer(new NullDatabaseInitializer<ApplicationDbContext>());
And then just manually run migrations when needed. To take it a step further, you can write your own initializer and do what you want when either the database does not exist or the database needs updating:
Database.SetInitializer(new ValidateDbInitializer<ApplicationDbContext>());
// ref: https://coding.abel.nu/2012/03/prevent-ef-migrations-from-creating-or-changing-the-database/
public class ValidateDbInitializer<TContext> : IDatabaseInitializer<TContext>
where TContext : ApplicationDbContext
{
public void InitializeDatabase(TContext context)
{
if (!context.Database.Exists())
{
throw new InvalidOperationException("The database does not exist. Check your server and connection string.");
}
if (!context.Database.CompatibleWithModel(true))
{
throw new InvalidOperationException("The database is not up to date. You may need to apply update(s).");
}
}
}
First step is to use the Tools menu, select Library Package Manager, then select Package Manager Console. In the Package Manager Console window type the below command.
Enable-Migrations
which will adds folder named as Migrations in your project and also a code file called as Configuration.cs.
in Configuration.cs type the below line
using yourprojectname.Models;
protected override void Seed(yourprojectname.Models.MyServiceContext context)
{
context.MyDB.AddOrUpdate(x => x.Id,
new MyData() { Name = "Mohit", CreatedDate= "14/05/2016" },
new MyData() { Name = "Prabhat", CreatedDate= "15/05/2016" },
);
}
Now type Update-Database
in Package Manager Console window
Try the following:
protected override void Seed(myDBdb)
{
var mProduct = new Product
{
Id = 1,
Name = "default product",
CreatedDate = DateTime.Now
};
db.Products.AddOrUpdate(mProduct);
db.SaveChanges();
}
When you are using the application for initialization the Data for the first time, please use DropCreateDatabaseAlways. e.g. :
public class MyClass : DropCreateDatabaseAlways<connectionstringContextName>
{
protected override void Seed(MyContext context)
{
// Your seed data
}
}

An object with the same key already exists in the ObjectStateManager (with specified fields)

I know this question has been asked a ton of times, but I think the fact that I'm specifying modified fields is making it a little tougher for me to solve. Here's my update method (in repository):
public Folder UpdateFolder(Folder folder)
{
_db.Folders.Attach(folder); // error happens here
var entry = _db.Entry(folder);
entry.Property(e => e.Title).IsModified = true;
SaveChanges();
return entry.Entity;
}
I get "An object with the same key already exists" when I try to Attach. If I remove that line, I get "The entity of type "folder" does not exist in this context".
Here's where I'm calling it from (test method):
homeFolder = _dtoServices.AddFolder(new FolderDto
{
Title = "Home Folder"
});
Assert.AreEqual(_dtoServices.GetHomeData().TotalFolders, 1);
// Check Folder
Assert.AreEqual(_dtoServices.GetFolder(homeFolder.FolderId).Details, "Home Folder");
// Update Folder, Check Folder
homeFolder.Title = "Updated";
_dtoServices.UpdateFolder(homeFolder); // HERE
Assert.AreEqual(_dtoServices.GetFolder(homeFolder.FolderId).Details, "Updated");
In my DtoServices:
public FolderDto UpdateFolder(FolderDto folderDto)
{
var test = _repository.UpdateFolder(folderDto.ToEntity());
return null;
}
In my FolderDto:
public class FolderDto
{
public FolderDto()
{
}
public FolderDto(Folder folder)
{
FolderId = folder.FolderId;
Title = folder.Title;
}
[Key]
public int FolderId { get; set; }
[Required]
public string Title { get; set; }
public Folder ToEntity()
{
var folder = new Folder
{
FolderId = FolderId,
Title = Title,
};
return folder;
}
}
Any idea why this happening?
The problem is most likely here: folderDto.ToEntity(). I guess in _dtoServices.AddFolder you have created a Folder entity and added it to the context, then called SaveChanges, then placed the generated Id in the returned homeFolder DTO. The entity Folder is still attached to the context and after SaveChanges in state Unchanged.
In UpdateFolder by calling folderDto.ToEntity() you create a new entity instance var folder = new Folder... with the same Id that you have returned from AddFolder. Then you attach this new instance to the same context where the old instance from AddFolder with the same key is still attached to ==> another "object with the same key" ==> exception.
Either detach the old entity before you attach the new one, or use Find to check if there isn't already an entity with the same key. If yes, update this entity and don't attach the other object.

Dependency Injection Query

I'm starting a web application that contains the following projects:
Booking.Web
Booking.Services
Booking.DataObjects
Booking.Data
I'm using the repository pattern in my data project only. All services will be the same, no matter what happens. However, if a customer wants to use Access, it will use a different data repository than if the customer wants to use SQL Server.
I have StructureMap, and want to be able to do the following:
Web project is unaffected. It's a web forms application that will only know about the services project and the dataobjects project.
When a service is called, it will use StructureMap (by looking up the bootstrapper.cs file) to see which data repository to use.
An example of a services class is the error logging class:
public class ErrorLog : IErrorLog
{
ILogging logger;
public ErrorLog()
{
}
public ErrorLog(ILogging logger)
{
this.logger = logger;
}
public void AddToLog(string errorMessage)
{
try
{
AddToDatabaseLog(errorMessage);
}
catch (Exception ex)
{
AddToFileLog(ex.Message);
}
finally
{
AddToFileLog(errorMessage);
}
}
private void AddToDatabaseLog(string errorMessage)
{
ErrorObject error =
new ErrorObject
{
ErrorDateTime = DateTime.Now,
ErrorMessage = errorMessage
};
logger.Insert(error);
}
private void AddToFileLog(string errorMessage)
{
// TODO: Take this value from the web.config instead of hard coding it
TextWriter writer = new StreamWriter(#"E:\Work\Booking\Booking\Booking.Web\Logs\ErrorLog.txt", true);
writer.WriteLine(DateTime.Now.ToString() + " ---------- " + errorMessage);
writer.Close();
}
}
I want to be able to call this service from my web project, without defining which repository to use for the data access. My boostrapper.cs file in the services project is defined as:
public class Bootstrapper
{
public static void ConfigureStructureMap()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry(new ServiceRegistry());
}
);
}
public class ServiceRegistry : Registry
{
protected override void configure()
{
ForRequestedType<IErrorLog>().TheDefaultIsConcreteType<Booking.Services.Logging.ErrorLog>();
ForRequestedType<ILogging>().TheDefaultIsConcreteType<SqlServerLoggingProvider>();
}
}
}
What else do I need to get this to work? When I defined a test, the ILogger object was null.
Perhaps some details on how you are calling this code from a test would be useful.
My understanding is that you need to ensure that the ConfigureStructureMap call has been made early in the applications life (e.g. in the Global.asax in a web project).
After that you would be calling for instances of IErrorLog using something like:
IErrorLog log = StructureMap.ObjectFactory.GetNamedInstance<IErrorLog>();

Resources