Today at work I was asked to add some basic logging functionality in my existing ASP.NET MVC (not Core) project. I was told to use Serilog for this.
However, I failed to find any reasonable example of using Serilog in MVC, all links simply refer to Core. I tried to do everything myself. After installing all necessary packages (Serilog, Serilog.Sinks.File), I created a "Logs" folder and tried this:
var log = new LoggerConfiguration()
.WriteTo.File("~/Logs/log.txt")
.CreateLogger();
log.Information("Hello from Serilog!");
I expected to see a new file in the folder but there wasn't any. I also tried using a simpler path "log.txt" and creating a file in this folder preemptively but it didn't help.
Is it possible that Serilog is not supported for MVC at all? If it is, what is a simple way to log something into a text file?
I doubt Serilog understands the ~/ syntax in your path to your log file. ~/ refers to the virtual root of your site, but Serilog doesn't know anything about virtual roots or websites. It's just a logging framework and expects a normal path. So if you want to log to a file called log.txt in the Logs directory of your site, then you need to convert it to a proper path that Serilog can understand.
The System.Web.Hosting.HostingEnvironment.MapPath method can translate virtual root relative paths. So ~/Logs/log.txt can become something like C:\path-to-your-site\Logs\log.txt.
Change to this:
var log = new LoggerConfiguration()
.WriteTo.File(System.Web.Hosting.HostingEnvironment.MapPath("~/Logs/log.txt"))
.CreateLogger();
log.Information("Hello from Serilog!");
//note that importing the namespace will make it so you don't have to fully qualify the name.
Then Serilog should log to the location you're expecting, if the directory exists and it has write privileges there.
File logging from a web application is going to get very messy. Unless your site gets hardly any usage, the logs are going to become unmanageable and useless. I suggest you look at the other Serilog sinks, and find one that logs to a logging service such as Seq (from the makers of Serilog) or Stackify Retrace.
Related
I have working web client, it uses "wwwroot/appsettings.json" file for its configuration.
Now I would like to override just single settings using environment variable for it (as an example, in reality there will be many, arbitrary, overrides). Is there ready to use mechanism, similar to ASP.NET Core server (all it takes is calling extension method and combining json, env. variables)?
I am not asking about multiple .json files and switching between them depending on ENVIRONMENT variable, it is completely different scenario.
So far I didn't find anything even close, so thinking about DIY approach I see an ugly path -- moving client configuration file into hosting server, adding main node in client .json file like "client", using environment variables with prefix "client", merging those data using ASP.NET server mechanism, dumping it back to file for the client usage. And hoping it will work :-).
So I followed DIY path :-) If anyone like it here are the steps:
create 3 files with empty JSON at web client wwwroot -- appsettings.json, appsettings.Development.json and Production version as well
put your entire web client config in appsettings.json at hosting server at "CLIENT" node for example
in your server Startup constructor create configuration as usual, but then fetch entire "CLIENT" section and "jsonize" it back (see: https://stackoverflow.com/a/62533775/6734314) -- convert it to string and write to $"wwwroot/appsettings.{env.EnvironmentName}.json" (where env is IWebHostEnvironment)
And that's it -- I tested it in Development mode and in Production. The only drawbacks I see are:
it looks weird :-)
when executed using VS the written file is put not relative to binary file, but relative to project -- so when you are done you have to delete newly created file (otherwise on the next run VS will complain about conflict between two static files)
You override the settings using env. variables at server side using "CLIENT" prefix, and the rest is as usual.
For the record, I am not saying this is perfect, but I didn't look for anything more than I asked in my question. What I would like to do however is to reduce the number of steps, or even better to use some already existing mechanism. I will be grateful for the improvements/tips within those areas.
I'm trying to use Realm Cloud in an Azure Function but it keeps giving me an error:
make_dir() failed: Permission denied Path: /realm-object-server/
Is there a way to configure Azure Functions to have permissions to create files? I'm new to Azure Functions, this is my first one so I'm not really sure of all the particulars.
I have found one solution to this. Inside Azure function, you can only create any file or folder inside the temp folder. So if you use following sync configuration, it should work. It worked for me.
var configuration = new FullSyncConfiguration(new Uri("/~/<your-realm-name>", UriKind.Relative), _realmUser, Path.Combine(Path.GetTempPath(), "realm-object-server"));
So basically, here you are passing the folder name to store the realm locally. If you don't pass the folder name, it will try to store it in a default location where you will get the access error.
I am not familiar with Realm, but functions has permissions to interact with the file system by default. See these links for information on the app service file system (this applies for functions too):
https://learn.microsoft.com/en-us/azure/app-service/operating-system-functionality#file-access
https://github.com/projectkudu/kudu/wiki/Understanding-the-Azure-App-Service-file-system
If the function is deployed using run from package, then the wwwroot is readonly. But since the path in the error message doesn't point to wwwroot, this is probably not the issue.
My best guess is that the code that is failing is trying to write to in an inappropriate location. The information in the links above should help resolve that. Maybe check to see if realm has a config setting that lets you specify which location it should be creating "realm-object-server" in.
You can use
SyncConfigurationBase.Initialize(UserPersistenceMode.NotEncrypted, basePath: Path.GetTempPath());
In an Azure Websites I was always using the following code to fetch some values from the config's app settings:
string property = WebConfigurationManager.AppSettings["property"];
Just a couple of days ago I stublemd upon CloudConfigurationManager, and with it I can get the property like so:
string property = CloudConfigurationManager.GetSetting("property");
Although CloudConfigurationManager seems like it's better fitted to cloud use, I never had any issues with WebConfigurationManager.
Should I be using CloudConfigurationManager?
What are the differences between the two?
In what cases CloudConfigurationManager will behave diffrent from
WebConfigurationManager?
CloudConfigurationManager enables us to read configuration file regardless of the environment we are in.
So instead of writing environment specific code statements e.g., for web.config file:
WebConfigurationManager.AppSettings["MySetting"]
For ServiceConfiguration.cscfg file:
RoleEnvironment.GetConfigurationSettingValue("MySetting")
We can write the below statement, which will read values from all the configuration files i.e., app.config, web.config and ServiceConfiguration.cscfg.
CloudConfigurationManager.GetSetting("MySetting")
CloudConfigurationManager requires Microsoft.WindowsAzure.Configuration assembly, part of Azure SDK or separate NuGet.
WebConfigurationManager requires System.Web.Configuration assembly, part of .NET Framework.
WebConfigurationManager and CloudConfigurationManager manage different configuration files.
WebConfigurationManager is for managing website's web.config file(s) and it's appsettings and connections strings
CloudConfigurationManager is for managing .cscfg files (for cloud services). His benefit is that you can manage configurations and connections from the azure portal directly.
I think you're better off using WebConfigurationManager.
With it, you have access to ConnectionStrings as well as AppSettings.
Both sets of settings you can update via the Azure Portal. They can then further be used in other Azure facilities/services, such as when configuring website backup.
Check this out for more information: https://azure.microsoft.com/en-us/blog/windows-azure-web-sites-how-application-strings-and-connection-strings-work/
Good day folks
I must have read about 20 different articles/approaches about how to implement log4net in ASP.NET 1.0 / 2.0 and various other application types.
Link #1
Link #2
Link #3
Well, above articles are all ok, i did try/follow all of them, but i never got a log file..
What i have:
IIS Hosted WCF Service.
What i want:
Logging using log4net - well, first i wanted to use Tracing (like Trace.Write in System.Diagnostics) then the Microsoft Enterprise Library and finally i'm stuck trying to figure out how to setup/configure log4net for my logging needs.
My question:
How to get log4net writing a logfile? i mean:
- is it a security problem? do i really need to procmon this?
- is the problem to write to a log file (security)?
- is the problem that the configuration file cannot be read?
i tried:
Specifying the log4net.config using
[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "log4net.config", Watch = true)]
Specifying the configuration in web.config after the block. When i did that i wasn't able to run the Web Application anymore (IIS reports corrupt web.config).
Help in this issue is really appreciated!
Christian
Ok, my fault. It was the declaration when ConfigFileExtension is declared, log4net searches for .dll. in the web root. Just changed that to ConfigFile and it's working like a charm. my careless mistake...!
Christian
I have an application written in .NET 3.5 with C# as the language. I'm using Web Forms, but using url routing with the routes defined in my global file. Everything is working as expected. In order for the pretty paths (see: user/665 instead of user.aspx?uid=665) to work properly, I had to add a wildcard mapping in IIS5.1 (local box, not test, staging, or production) the aspnet_isapi file for the 2.0 framework. Everything works fine.
Now, my site needs a plugin for PHP. However, the PHP files are now being serviced by ASP.NET due to the wild card mapping, and hence are not processed by the PHP interpretter. Is there any way to get around this? Would I have to add some sort of handler to my web app that will take all PHP requests being handled by the ASP.NET framework and have them routed to the PHP engine? Is there an easier way? Maybe a way to exclude them in the web.config (PHP files) and have them served by the proper PHP engine?
Thanks all!
-Steve
This is a solution, but is not an elegant way (IMHO):
Create a virtual directory
Have it point to the folder with the files (in this case, a PHP plugin)
Give it the proper permissions
Change the config options for the virtual directory in IIS and make sure the wildcard mapping for that directory is removed.
This works like a charm for my situation. However, is there any way to not have to deal with virtual directories?
The problem is that the PHP extension needs to be registered.
In IIS Manager right-click on Default Website -> Properties -> Home Directory -> Configuration
Under Application Mappings make sure that .php is added and is it pointing to PHP.EXE. There should be an entry like this: extension .php, executable path C:\PHP\PHP.EXE %s %s
From what I gather, the problem is that ASP.NET is attempting to route your PHP requests, so what I would do is add a StopRoutingHandler() to your routes in the global.asax. Something like this should work:
routes.Add(new Route("{resource}.php/{*pathInfo}", new StopRoutingHandler()));
Edit: Be mindful that routes are processed in order, so I would add this to the top of your routes.