PreCompile ASP.net mvc - asp.net

I believe you can pre compile a asp.net mvc application but there are some issues with aspx files.
Is it correct to say the view folder needs to be copied to the deployed location?
If so does anyone know why?
Thanks

The short answer is that ASPX (and ASCX) files don't get compiled and must be copied with your application when you deploy to IIS.
You can precompile an ASP.NET MVC application, but the ASPX/ASCX files don't get included in the mix. In our experience, we weren't able to use aspnet_compiler.exe to bundle everything into a binary, so we use csc (via nant) to compile all of the stuff that can be compiled, and then copy the rest. This includes the View folder.
If it helps, the relevant portion of one of our nant scripts is as follows:
(Assuming all dependencies have already been copied to the site folder's (BuildDir in this case) bin folder)
<csc target="library" output="${BuildDir}/bin/${FinalDeployDllName}.dll" >
<references failonempty="true">
<include name="${BuildDir}/bin/SomeDependency.dll" />
</references>
<sources>
<include name="${BuildDir}/**/*.cs" />
</sources>
</csc>
<copy todir="${target}" overwrite="true">
<fileset basedir="${BuildDir}">
<include name="**/*.???x" />
<include name="**/*.js" />
<include name="**/*.jpg" />
<include name="**/*.jpeg" />
<include name="**/*.gif" />
<include name="**/*.png" />
<include name="**/*.html" />
<include name="**/*.css" />
<include name="**/*.swf" />
<include name="**/*.Master" />
<include name="**/Web.config" />
<include name="images/**/*" />
<include name="bin/**/*" />
<include name="Content/**/*" />
</fileset>
</copy>
<delete>
<fileset>
<include name="${target}/*.build" />
<include name="${target}/*.scc" />
<include name="${target}/*.sln" />
<include name="${target}/*.suo" />
<include name="${target}/build.*" />
<include name="${target}/*.resharper" />
<include name="${target}/*.resharper.user" />
<include name="${target}/bin/*.xml" />
<include name="${target}/bin/*.pdb" />
</fileset>
</delete>
This'll create a folder at {target} with all the required files for deployment, to be packaged from there as you see fit.

I've always used Web Deployment Projects to precompile web applications and prepare them for deployment. Scott Guthrie has blogged about it.

Related

Spring MVC x wildfly 17 x logbackconfiguration

So I have a project for which I need to set up logback. This project is strictly spring MVC(can't be upgraded to spring-boot). It is deployed on wildfly 17.0.1.
I have a few questions regarding this.
So I did the setup of logback and logs are generated fine. But auto scan of the configuration file logback.xml is not working.
My setup
This is the only dependency I've added to my project. Logback is set up to bridge via slf4j(set up in wildfly)
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.9</version>
</dependency>
This is my logback.xml file.
<configuration scan="true" scan_period="2 seconds" debug="false" packagingData="false">
<property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
<property name="LOG_DIR" value="path/to/dir" />
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/server.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- <level>INFO</level>-->
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/server.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>365</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<appender name="APP_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/app.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- <level>INFO</level>-->
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/uix.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>365</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<appender name="ACCESS_APP_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/access.app.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- <level>INFO</level>-->
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/access.app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>365</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
</root>
<logger name="com.package.path" level="INFO" additivity="false">
<appender-ref ref="ACCESS_APP_FILE"/>
</logger>
<logger name="com.package.path.2" level="INFO" additivity="false">
<appender-ref ref="APP_FILE"/>
</logger>
</configuration>
This logback.xml file is placed in wildfly's standalone folder for me to be able to change the runtime log level(reference to logback.xml is given in standalone.sh). But this is not working and after searching for it, people suggested putting it in the target folder which does not make sense(since I then can't change the log level once *.war is deployed).
So can someone suggest what can be done here where I can achieve changing log level at runtime?
The console Appender does not work at all. Logs that are supposed to be seen in the console, are stored in a log file. But I also want them to be displayed on the console too. I'm using the same configuration file as above. Can you help me with this too?
Things I've done
Added jboss-deployment-structure.xml and excluded other logging libraries from wildfly or even my own project.
Setting LogContext and setting configuration file in the project which also didn't work.
Any help is much appreciated :)

How to configure dotnet core web app for different environments under IIS

We have a dotnet core 3.1 web app which we are trying to host under IIS 6. This all works fine on the hosted DEV environment, but when we move to the integration (or later) environment the application fails to start and does not get as far as logging anything to Insights.
The .csproj file looks like this:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.7" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
</ItemGroup>
</Project>
On the development environment we have this web.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\MyApp.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="OutOfProcess">
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
<environmentVariable name="ASPNETCORE_URLS" value="https://dev-apps.myapp.com/MyApp" />
<environmentVariable name="LOCAL" value="false" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</location>
</configuration>
This works perfectly. However, if we change the ASPNETCORE_ENVIRONMENT value to Integration (as we would when deploying to the integ environment) the application fails with a 500 error.
I tried adding this line to the working web.config, but it appeared to have no effect (as mentioned in this documentation):
<environmentVariable name="DOTNET_ENVIRONMENT" value="Integration" />
How can I tell the application that it is hosted in a non-dev environment and thus to use the appsettings.*.json for that environment?
Our settings files are these:
appsettings.json
appsettings.Development.json
appsettings.Integration.json
appsettings.ProdSupport.json
appsettings.Production.json
We are not using dotnet publish but are simply building using:
dotnet build MyApp.csproj
In this case it turned out that we were using the PersistKeysToFileSystem method of persisting the data protection keys across multiple servers. This was failing because, in that environment, the one server did not have permission to write to the next in that location.

Setting up different log4net logging levels based on transformations in web.config?

I have installed log4net, and have the following setup:
<configuration>
<log4net debug="true">
<!-- two appenders -->
<root>
<level value="DEBUG" />
<appender-ref ref="AdoNetAppender" />
<appender-ref ref="SlackAppender" />
</root>
</log4net>
</configuration>
This is perfect, because locally I want to debug everything two my appenders.
Now, I want to log only errors in production.
I tried to edit my Web.release.config I am quite sure I didn't do it correctly:
<log4net debug="true">
<root>
<level value="ERROR" xdt:Transform="Replace" xdt:Locator="Match(key)" />
</root>
</log4net>
</configuration>
Because it doesn't have a key, so I cannot do this.
What is the best practice here?

log4net doesn't create log file when deployed on IIS7

Good morning everybody,
I have a log4net issue that didn't exist when I was developing on my
local machine, but once I deployed the application to a server, log4net stopped working.
This is the server configuration :
-Windows XP SP3
-IIS 7
-framework .Net v4
This is the log4net configuration in the web.config of the website:
<configuration>
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="log.txt" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="30MB" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" />
</layout>
</appender>
</log4net>
</configuration>
I also have a class library and this is its App.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
</configSections>
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" >
<param name="File" value="log.txt" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="30MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" />
</layout>
</appender>
</log4net>
</configuration>
This is how I call the log function on every class:
private static readonly ILog log = LogManager.GetLogger(typeof(AppDomain));
...and this is how i call it :
log.Error("\n\t=>" + ex.GetBaseException().Message + "\n\r" + " # " + Environment.StackTrace);
It could be that you do not have permissions to write to the file 'log.txt'.
I don't know what the current directory would be but it's unlikely to be somewhere IIS can write to.
You need to create a folder somewhere and grant access for IIS to write to it, I understand you need to grant access to the IIS_IUSRS group and then specify the absolute path to that file. e.g.
<param name="File" value="D:\Logs\log.txt" />
..using the path to your preferred location.
When it comes to writing log files I tend not to try and write my log files anywhere in the program files directory or anything in any virtual directory just because of the previous battles I've had with security issues. Currently I'm using something like the following for all my log4net log files:
<file type="log4net.Util.PatternString" value="${ALLUSERSPROFILE}/<Product Name>/Logs/<Program Name>/<Program Name>.log" />
${ALLUSERSPROFILE} is the key above. This directory typically doesn't have the security restrictions as virtual directory and the program files directory. I've found that I haven't had any trouble since I've been using this path.
This envrionment variable takes you to the ProgramData directory in Windows Vista, 7, 8, Server 2008 etc. I think XP takes you to a different place but still a directory with relaxed permissions.
On a side note your log statement above:
log.Error("\n\t=>" + ex.GetBaseException().Message + "\n\r" + " # " + Environment.StackTrace);
Can be shortened to: log.Error(ex); Unless the formatting is a must. But if you write it like that and deploy your binaries with the pdbs the exceptions you log will contain the full stack trace and the line number the error occurred on.
Edit:
Log files will also fail to create if you have invalid log4net configuration. If you are sure that you have write access to the folder specified in your log4net configuration I would suggest enabling log4net debugging by first setting debug="true" in your log4net config section:
<log4net debug="true">
...
</log4net>
Setting the above debug flag will tell log4net to output all it's logging via windows trace listeners. To capture this trace listener output you will have to add a section like the following to your app.config:
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add
name="textWriterTraceListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="C:\tmp\log4net.txt" />
</listeners>
</trace>
</system.diagnostics>
Make sure the path specified in the above trace listener config in app.config exists and that you have write access to the folder!
I had the same problem myself and it turned out that I had forgot to set the "Build Action" for the configuration file. Therefore the log4net.config file was not deployed, and this is of course needed to make the application write the log file.
The log folder directory should be given the permission under which IIS is running. e.g. if IIS is run as network service then add Network service account the directory and give full permission to it.
Check with reference to following configuration in web.config. If everything good , check the write permission of inetpub sub-folder using the application pool owner. If not grant full permission.
Hope it will resolve your issue
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net debug="true">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="logs\log.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n %newline--%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />
</root>
</log4net>

Can Log4net have multiple appenders write to the same file?

I'm using a RollingFileAppender to log some info to a file with a conversionPattern (in the web.config) that looks like this for the header of each log section:
<conversionPattern value="%date - %property{userId} - %property{method}%newline--------------------------------%newline%message%newline%newline"/>
I'd like to log details under this header as bullet points. I'm currently trying to use another RollingFileAppender that logs to the same file with a simple conversionPattern of just a dash, like this:
<conversionPattern value="- %message%newline"/>
But these messages aren't making it into the log file. I'm using Log.Info() for the header and Log.Debug() for the bullet points and filtering each appender on their respective log levels. Is what I'm trying to do possible? Or is there a better way to get header and detail information into a log file from log4net?
Yes you can have two log4net appenders that append (write) to the same log file.
You need to place the following line in each of your Appenders:
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
This will make log4net use a minimal locking model that allows multiple processes to write to the same file.
Here's an example XML that uses two appenders writing to the same log file:
<log4net debug="false">
<appender name="RollingLogFileAppender1" type="log4net.Appender.RollingFileAppender">
<!-- this configures a log for the application messages -->
<file value="TestLog.log" />
<appendToFile value="true" />
<!-- next line uses a minimal locking model that allows multiple processes to write to the same file -->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<!-- make the most recent log the highest numbered log -->
<countDirection value="1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date{MM-dd-yyyy HH:mm:ss.ff} [%property{NDC}] %message%newline [Thread: %thread] %c{1} Method:%method(%file{1}, Line:%line) %newline" />
</layout>
<!-- The following two filters insure only log requests of
version '1' use this Appender -->
</appender>
<appender name="RollingLogFileAppender2" type="log4net.Appender.RollingFileAppender">
<file value="TestLog.log" />
<appendToFile value="true" />
<!-- next line uses a minimal locking model that allows multiple processes to write to the same file -->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<!-- make the most recent log the highest numbered log -->
<countDirection value="1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date{MM-dd-yyyy HH:mm:ss.ff} [%property{NDC}] [Thread: %thread] %c{1} Method:%method(%file{1}, Line:%line) %newline%message" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender1" />
<appender-ref ref="RollingLogFileAppender2" />
</root>
This can be found in the Apache documentation here:
Apache Log4Net Docs
Just search on this page for 'same file'.
Hope this helps.
You could realize if there is any problem with log4net checking the output window on visual studio. The library log errors there, very useful to detect configuration mistakes.

Resources