I started a macOS project using Default configuration of CoreData. Application was released and some users started to use it. Now, I need some data to be synced with iCloud and some data to be only stored locally. If I understand correctly, the only way I can achieve this is to create two different configurations (in CoreData data model), add the needed entities in each configuration, and configure the NSPersistentContainer accordingly.
However the above method might lead to some data loss since I wont be using the Default configuration anymore.
Is there any way I can "migrate" the data saved under the Default configuration to another configuration?
After some trial and error I found a solution that seems to do the work (however, it seems dirty).
First, when instantiating the container, I make sure I add my 3 storeDescriptors to persistentStoreDescriptions (each representing an scheme)
let defaultDirectoryURL = NSPersistentContainer.defaultDirectoryURL()
var persistentStoreDescriptions: [NSPersistentStoreDescription] = []
let localStoreLocation = defaultDirectoryURL.appendingPathComponent("Local.sqlite")
let localStoreDescription = NSPersistentStoreDescription(url: localStoreLocation)
localStoreDescription.cloudKitContainerOptions = nil
localStoreDescription.configuration = "Local"
persistentStoreDescriptions.append(localStoreDescription)
let cloudStoreLocation = defaultDirectoryURL.appendingPathComponent("Cloud.sqlite")
let cloudStoreDescription = NSPersistentStoreDescription(url: cloudStoreLocation)
cloudStoreDescription.configuration = "iCloud"
cloudStoreDescription.cloudKitContainerOptions = "iCloud.com.xxx.yyy"
persistentStoreDescriptions.append(cloudStoreDescription)
let defaultStoreLocation = defaultDirectoryURL.appendingPathComponent("Default.sqlite")
let defaultStoreDescription = NSPersistentStoreDescription(url: defaultStoreLocation)
defaultStoreDescription.cloudKitContainerOptions = nil
defaultStoreDescription.configuration = "Default"
persistentStoreDescriptions.append(defaultStoreDescription)
container.persistentStoreDescriptions = persistentStoreDescriptions
Note: One important thing is to make sure that NSPersistentStoreDescription with the Default configuration is added last.
Secondly, I am for-eaching thought all data saved in core data checking if managedObject.objectID.persistentStore?.configurationName is "Default" (or any string containing Default. With my empiric implementation I got to the conclusion that configuration name might be different from case to case). If the above condition is true, create a new managedObject, I copy all properties from the old one to new one, delete the old managed object, and save the context.
for oldManagedObject in managedObjectRepository.getAll() {
guard let configurationName = oldManagedObject.objectID.persistentStore?.configurationName else {
continue
}
if (configurationName == "Default") {
let newManagedObject = managedObjectRepository.newManagedObject()
newManagedObject.uuid = oldManagedObject.uuid
newManagedObject.createDate = oldManagedObject.createDate
......
managedObjectRepository.delete(item: oldManagedObject)
managedObjectRepository.saveContext()
}
}
With this implementation, old data that was previously saved in Default.sqlite is now saved in Local.sqlite or 'Cloud.sqlite' (depending on which configuration contains which entity).
I'm trying to use swift with keystone authentication. I followed this link https://docs.openstack.org/swift/latest/overview_auth.html#keystone-auth to edit my proxy-server.conf but I noticed that at the bottom of the file [filter:authtoken] is already there, while in the comments section I can uncomment a section with the same name of [filter:authtoken], right now the bottom part looks like this:
[filter:authtoken]
include_service_catalog = False
cache = swift.cache
delay_auth_decision = 1
memcached_servers = localhost:11211
cafile = /opt/stack/data/ca-bundle.pem
project_domain_name = Default
project_name = service
user_domain_name = Default
password = 1234
username = swift
auth_url = http://10.180.204.223/identity
interface = public
auth_type = password
What should I do with it? Should I keep it, modify it according to the link, or should I uncomment the section and add the code according to the link?
For our reporting environment, we allow users to run reports "online" (the code for this is based on CrystalDecisions.ReportAppServer.ClientDoc.ReportClientDocument) or "offline" which is to schedule them on the Business Objects server directly. This code is based on CrystalDecisions.Enterprise.Desktop.Report.
For the online report, we're able to programmatically set the provider with this code:
If crTableNew.ConnectionInfo.Kind = CrConnectionInfoKindEnum.crConnectionInfoKindCRQE Then
crLogonInfo = CType(crAttributes("QE_LogonProperties"), PropertyBag)
crLogonInfo("Data Source") = serverName
crLogonInfo("Initial Catalog") = databaseName
crLogonInfo("Provider") = "SQLNCLI11"
End If
However, the equivalent code for offline doesn't seem to expose the "Provider" property. The equivalent object is roughly this:
CrystalDecisions.Enterprise.Desktop.Report.ReportLogons.Item(tableIndex) but none of the properties there seem to be the Provider.
Anyone able to help?
The closest corresponding ReportLogon property to the LoginInfo Provider property is the ServerType property. However, I don't think you need this in order to set the database credentials.
You can probably do something like this
foreach(ReportLogon reportLogon in reportLogons)
{
reportLogon.UseOriginalDataSource = false;
reportLogon.CustomServerName = serverName;
reportLogon.CustomUserName = userId;
reportLogon.CustomPassword = password;
reportLogon.CustomDatabaseName = databaseName;
foreach(TablePrefix tablePrefix in reportLogon.TableLocationPrefixes)
{
tablePrefix.MappedTablePrefix = databaseName + ".dbo.";
tablePrefix.UseMappedTablePrefix = true;
}
}
Looping through the TableLocationPrefixes ensures that all referenced tables or sprocs are associated to the database specified in the logon credentials.
I would like to increase the MaxBufferSize, MaxBufferPoolSize, ReceivedMessageSize, along with the readerQuotas maxDepth="2147483646" maxStringContentLength="2147483646" maxArrayLength="2147483646" maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646", It is my understanding that I must change these parameters in the registration process. But I see no examples anywhere on doing this.
I would appreciate any help on this matter.
Don't know if you found an answer to this or not but it would look something like this:
builder.Register(
container =>
new ChannelFactory<TService>(
new WSHttpBinding { TransactionFlow = supportTransactionFlow,
MaxReceivedMessageSize = 2147483646,
ReaderQuotas = {
MaxStringContentLength = 2147483646,
MaxDepth = 2147483646,
MaxArrayLength= 2147483646 }},
endpointAddress)).InstancePerDependency();
I have a win form that creates a site in IIS7.
One function needs to open the web.config file and make a few updates. (connection string, smtp, impersonation)
However I do not have the virtual path, just the physical path.
Is there any way I can still use WebConfigurationManager?
I need to use it's ability to find section and read/write.
System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration
You will have to map the physicalPath to a virtualPath. Here is how you would do that.
using System.Web.Configuration; //Reference the System.Web DLL (project needs to be using .Net 4.0 full, not client framework)
public static Configuration OpenConfigFile(string configPath)
{
var configFile = new FileInfo(configPath);
var vdm = new VirtualDirectoryMapping(configFile.DirectoryName, true, configFile.Name);
var wcfm = new WebConfigurationFileMap();
wcfm.VirtualDirectories.Add("/", vdm);
return WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/");
}
Vadim's answer worked great on our dev server, but bombed out on our live server with the following message:
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: site
To correct this, I found another overload for WebConfigurationManager.OpenMappedWebConfiguration that takes the IIS website name as the third parameter. The result is as follows:
public static Configuration OpenConfigFile(string configPath)
{
var configFile = new FileInfo(configPath);
var vdm = new VirtualDirectoryMapping(configFile.DirectoryName, true, configFile.Name);
var wcfm = new WebConfigurationFileMap();
wcfm.VirtualDirectories.Add("/", vdm);
return WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/", "iis_website_name");
}
Vadim's answer was exactly what I needed, but I came across the same issue as Kieth, and his solution did the trick!
I thought I'd add though, that the IIS Website name can be retrieved by calling:
System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteName();
Also, cjbarth's code included a tidy solution for those testing in environments where the location of wwwroot and Web.config can vary:
System.Web.HttpContext.Current.Server.MapPath("~");
So with these in mind another slight improvement on Vadim's function would read:
public static Configuration GetWebConfig() {
var webConfigFile = new FileInfo("Web.config");
var wwwRootPath = HttpContext.Current.Server.MapPath("~");
var vdm = new VirtualDirectoryMapping(wwwRootPath, true, webConfigFile.Name);
var wcfm = new WebConfigurationFileMap();
wcfm.VirtualDirectories.Add("/", vdm);
var siteName = HostingEnvironment.ApplicationHost.GetSiteName();
return WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/", siteName);
}
I ended up using Powershell.
$file = "D:\Applications\XXX\Private\XXX\XXXX\web.config"
$configurationAssembly = "System.Configuration, Version=4.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a"
[Void] [Reflection.Assembly]::Load($configurationAssembly)
$filepath = New-Object System.Configuration.ExeConfigurationFileMap
$filepath.ExeConfigFileName = $file
$configuration = [System.Configuration.ConfigurationManager]::OpenMappedExeConfiguration($filepath,0)
$section = $configuration.GetSection("appSettings")
Write-Host "Set the Protection Provider"
if (-not $section.SectionInformation.IsProtected)
{
$section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider")
$configuration.Save()
}
Building on Vadim's answer, I found what he wrote didn't exactly work for my situation, so I used this instead:
Dim connectionSettings As New ConnectionStringSettings("mySQLite", ConnectionStringHelper.MyConnectionString)
Dim dummyVirtualPath As String = "/MyApp"
Dim virtualDirMap = New VirtualDirectoryMapping(Server.MapPath("~"), True)
Dim webConfigFileMap = New WebConfigurationFileMap()
webConfigFileMap.VirtualDirectories.Add(dummyVirtualPath, virtualDirMap)
Dim mappedConfigFile = WebConfigurationManager.OpenMappedWebConfiguration(webConfigFileMap, dummyVirtualPath)
Dim config As System.Configuration.Configuration = mappedConfigFile WebConfigurationManager.OpenWebConfiguration(Server.MapPath("~") & "/")
Dim csSection As ConnectionStringsSection = config.ConnectionStrings
If csSection.ConnectionStrings("mySQLite") IsNot Nothing AndAlso csSection.ConnectionStrings("mySQLite").ConnectionString <> connectionSettings.ConnectionString Then
csSection.ConnectionStrings("mySQLite").ConnectionString = connectionSettings.ConnectionString
config.Save()
ConfigurationManager.RefreshSection(csSection.SectionInformation.Name)
End If
In case anyone else is trying what I'm trying and finds this, the purpose of my doing this was to get SimpleMembershipProvider, which inherits from ExtendedMembershipProvider, to work with SQLite. To do that, I created the tables manually per this link: SimpleMembershipProvider in MVC4, and then used this command in my Global.asax file's Application_Start routine:
WebSecurity.InitializeDatabaseConnection(ConnectionStringHelper.MyConnectionString, "System.Data.SQLite", "Users", "UserID", "Email", False)
Which it turns out didn't require me to actually re-write my web.config file at all. (There were also a lot of web.config changes I had to do, but that is even more out of the scope of this question.)