I have a silverlight application that went it starts up, it needs to read a config file that a webservice returns.
So, in my main page, I want something like this:
public MainPage()
{
InitializeComponent();
Config cfg = new Config();
XDocument config = cfg.getConfig();
//doing stuff with config here
...
}
The constructor for config calls readConfigAsnc and I have a method for the readcompleted that returns the xdocument. I want the readConfigCompleted called before execution continues in MainPage(). What is the best way to go about doing this?
The best way is to separate this out into two methods. Pass a function as a parameter of the getConfig, so like this:
cfg.getConfig( fcnToCall );
Later, in your code,
void fcnToCall( XDocument config )
{
//Do stuff with config here...
}
Another option would be to use lambda expression if you want to retain your local variables:
Config cfg = new Config();
cfg.Callback += new Action<XDocument> action = s =>
{
XDocument cfg = s as XDocument;
//Do stuff with config here...
};
cfg.getConfig();
Why not separate out the methods? Instead of having all of this happen in the MainPage(), have the 'Do Stuff' happen in the GetConfigCompleted event.
Related
In my asp.net application, I'm using ConsoleLogger when debug.
services.AddLogging(builder => builder.AddConsole());
In integration tests, I'm trying to obtain console output like this
var strWriter = new StringWriter();
Console.SetOut(strWriter);
// some code that has a lot of logging
var consoleOutput = strWriter.ToString();
and consoleOutput is an empty string.
Is that issue with ConsoleLogger? How can I obtain console output?
Not sure why you want to do this and even more - I would say you should not do this, at least this way, but if you still want - you will need Console.SetOut before writing first messages to log, i.e. in case of ASP.NET Core it should look something like this:
public static StringWriter GlobalStringWriter = new StringWriter(); // use this "singleton"
public static void Main(string[] args)
{
Console.SetOut(GlobalStringWriter);
CreateHostBuilder(args).Build().Run();
}
Note that it will capture all concurrent requests (as it should do anyway).
If you take a look at source code for ConsoleLoggerProvider (which is actually setup with AddConsole call), you will see that in internally uses AnsiLogConsole/AnsiParsingLogConsole both of which internally capture current value of System.Console.Error/System.Console.Out in theirs constructors:
public AnsiParsingLogConsole(bool stdErr = false)
{
_textWriter = stdErr ? System.Console.Error : System.Console.Out;
_parser = new AnsiParser(WriteToConsole);
}
public AnsiLogConsole(bool stdErr = false)
{
_textWriter = stdErr ? System.Console.Error : System.Console.Out;
}
So setting the string writer after this capture happened does not actually change where logs are written.
I would say that this is not very good approach and possibly you better think about implementing some kind of your own logger provider which will allow you to handle this usecase, or use an existing one and set it up for debug mode to write to file.
I'm new to NHibernate and I'm trying to configure it based on the book 'Learning NHibernate 4'. However, I'm stuck with how to configure it. I have a class called Connection but when I try to use it, NHibernate tells me it can't find 'HbmMapping'.
class Connection
{
public Connection()
{
var cfg = new Configuration();
cfg.DataBaseIntegration(x =>
{
x.Dialect<PostgreSQLDialect>();
x.Driver<NpgsqlDriver>();
x.ConnectionString = "Server=127.0.0.1; Port=5433; User Id=smartwarehouse; Password=$smart#2018;Database=warehouse;";
x.ConnectionReleaseMode = ConnectionReleaseMode.OnClose;
x.LogSqlInConsole = true;
x.LogFormattedSql = true;
}).AddMapping(GetMappings());
}
// here is Hbm dosn't find from library
private HbmMapping GetMappings()
{
}
}
it gives me other two options to use like here
This is probably a better resource for this issue. You typically tell it where your mappings are at an assembly level...
.AddFromAssemblyOf<YourEntity>();
...so that when you add/remove mappings, you don't need to change your code.
For example, my SessionProvider has a bit like this:
Config = new NHibernateConfig();
Config.Configure(); // read config default style
Fluently
.Configure(Config)
.Mappings(
m => m.FluentMappings.AddFromAssemblyOf<UserMap>()
...
I don't have .hbm files as I use derivatives of ClassMap. However, as long as the type you specify in the AddFromAssemblyOf method is in the same assembly as your .hbm files, then it should work. So something like:
Fluently
.Configure(Config)
.Mappings(
m => m.HbmMappings.AddFromAssemblyOf<ATypeInYourMappingAssembly>()
I have a quartz configuration section in my web.config, and I want to add a key value field to it. (I know I can just go to the web.config and add it manually but that defeats the purpose)
I tried using this way
var config = (NameValueCollection)WebConfigurationManager.GetSection("quartz");
config.Add("quartz.dataSource.quartzDS.connectionString", "data source =..");
but it failed because collection is read only and can't be modified. Any tip to how to do this?
Edit: I ended up copying the config to a nameValueCollection and then copying it to another one (for the readonly properties) add the key values I want and passing it to the function I needed.
var oldConfig = (NameValueCollection)WebConfigurationManager.GetSection("quartz");
var config = Test(oldConfig);
var connectionString = unitOfWork.GetConnectionStringByTenantIdentifier(tenantId);
config.Add("quartz.dataSource.quartzDS.connectionString", connectionString);
await unitOfWork.GetService<SchedulerService>().StartScheduler(config, tenantId);
this way I will have the custom configuration for every tenant the way I want it. Sorry if my question wasn't clear.
You can actually do this in two ways.
One way is to set your dynamic connection string in the standard AppSettings section and then create a new Quartz Scheduler with a new set of XML properties (an example is provided in Quartz.NET distribution, so I will cut this short)
var properties = new NameValueCollection
{
["quartz.scheduler.instanceName"] = "XmlConfiguredInstance",
["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz",
... etc.
};
ISchedulerFactory sf = new StdSchedulerFactory(properties);
IScheduler sched = await sf.GetScheduler();
Then you can save your non-const string in the AppSettings and get it form there.
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings.Add("quartz.dataSource.quartzDS.connectionString", connstring);
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
Or you can read your whole settings file as XML, as previously answered, BUT you have to make sure that any edits are done before you initialize the default Quartz Scheduler, as it's properties become read-only, and to change them you will have to create a new ISchedulerFactory anyway, which kinda beats the purpose.
var xmlDoc = new XmlDocument();
xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
xmlDoc.SelectSingleNode("//quartz/add[#key='quartz.dataSource.quartzDS.connectionString']").Attributes["value"].Value = "...";
xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
ConfigurationManager.RefreshSection("quartz");
But I advise you not to edit your main config file at runtime at all, and instead use an ISchedulerFactory XmlConfiguredInstance while getting and saving the connstring into a UAC-compatible location in any format you like (to prevent Modifying app.config at runtime throws exception from happening)
Still if you want to use the config file you can use this tutorial from Yi Zeng for further reading
You can try using XmlDocument classes to go to a lower level.
Make sure the user of your app has write permissions to the config file
public static void WriteKey(String configFileName, String key, String value)
{
XmlDocument doc = new XmlDocument();
doc.Load(configFileName);
XmlNode node = doc.SelectSingleNode("//quartz");
if (node == null)
{
throw new InvalidOperationException("quartz section not found in config file.");
}
try
{
XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
if ((elem != null))
{
elem.SetAttribute("value", value);
}
else
{
elem = doc.CreateElement("add");
elem.SetAttribute("key", key);
elem.SetAttribute("value", value);
node.AppendChild(elem);
}
doc.Save(configFileName);
}
catch
{
throw new InvalidOperationException("Error writing config file");
}
}
I would like to read, modify and write back csproj files.
I've found this code, but unfortunately Engine class is depreciated.
Engine engine = new Engine()
Project project = new Project(engine);
project.Load("myproject.csproj");
project.SetProperty("SignAssembly", "true");
project.Save("myproject.csproj");
So I've continued based on the hint I should use Evaluation.ProjectCollection instead of Engine:
var collection = new ProjectCollection();
collection.DefaultToolsVersion = "4.0";
var project = new Project(collection);
// project.Load("myproject.csproj") There is NO Load method :-(
project.FullPath = "myproject.csproj"; // Instead of load? Does nothing...
// ... modify the project
project.Save(); // Interestingly there is a Save() method
There is no Load method anymore. I've tried to set the property FullPath, but the project still seems empty. Missed I something?
(Please note I do know that the .csproj file is a standard XML file with XSD schema and I know that we could read/write it by using XDocument or XmlDocument. That's a backup plan. Just seeing the .Save() method on the Project class I think I missed something if I can not load an existing .csproj. thx)
I've actually found the answer, hopefully will help others:
Instead of creating a new Project(...) and trying to .Load(...) it, we should use a factory method of the ProjectCollection class.
// Instead of:
// var project = new Project(collection);
// project.FullPath = "myproject.csproj"; // Instead of load? Does nothing...
// use this:
var project = collection.LoadProject("myproject.csproj")
Since i can't comment:
This won't work in .net core without first setting the MSBuild.exe path variable. The code to do so can be found here
https://blog.rsuter.com/missing-sdk-when-using-the-microsoft-build-package-in-net-core/
and is written here
private static void SetMsBuildExePath()
{
try
{
var startInfo = new ProcessStartInfo("dotnet", "--list-sdks")
{
RedirectStandardOutput = true
};
var process = Process.Start(startInfo);
process.WaitForExit(1000);
var output = process.StandardOutput.ReadToEnd();
var sdkPaths = Regex.Matches(output, "([0-9]+.[0-9]+.[0-9]+) \\[(.*)\\]")
.OfType<Match>()
.Select(m => System.IO.Path.Combine(m.Groups[2].Value, m.Groups[1].Value, "MSBuild.dll"));
var sdkPath = sdkPaths.Last();
Environment.SetEnvironmentVariable("MSBUILD_EXE_PATH", sdkPath);
}
catch (Exception exception)
{
Console.Write("Could not set MSBUILD_EXE_PATH: " + exception);
}
}
In my App.xaml.cs I have
private void InitializeContainer()
{
var catalogs = new AggregateCatalog();
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
catalogs.Catalogs.Add(catalog);
// Also adding Interactions project
catalog = new AssemblyCatalog(typeof(InteractionsService).Assembly);
catalogs.Catalogs.Add(catalog);
// initialize the main application composition host (container)
CompositionHost.Initialize(catalogs);
}
However, when I try to get object initialized down a line like so:
this.InteractionsService = ServiceLocator.Current.GetInstance<IInteractionsService>();
I get exception that my ServiceLocator.Current is null.
How do I make it work?
I had the very same question..
and found this which might be helpful,
http://www.itwox.com/post/Using-MEF-with-Common-Service-Locator.aspx
the key statement is
ServiceLocator.SetLocatorProvider(() => whateveryourlocatorinstanceis );
I think you're missing the call to ComposeParts or Compose in the set up of the CompositionContainer . Before you start to resolve instances via GetInstance.
There's an MSDN walk through here, and some other samples here and here. The relevant code snippet:
private CompositionContainer _container
//your code
var batch = new CompositionBatch();
batch.AddPart(this);
_container.Compose(batch);
//or more simply
_container.ComposeParts(this) //if this method is supported