404 when WebAPI 2 Controller is called - asp.net

i have developed a simple WebAPI 2 Controller with only one Controller and some simple GET Methods. I have created for this a Visual Studio 2015 Emtpy ASP.Net Web Application and added a WebAPI 2 Controller to it.
I have published it to a Windows 2012 R2 Machine with IIS 8.5 and ASP.Net 4.0 installed on it. It has thelatest updates etc.
When i call the Method from a browser i get an error 404 - 0x80070002 Notification: MapRequestHandler
You can download my solution here: VS2015 WebAPI2 Solution
This is the error message:
This is my webapplication:
These are the handlers:
This is the WebApplication configuration:
This is the Application Pool configuration:
These are the ISAPI filters:
Has anybody an idea about the possible reason why this it not working?
This is my controller:
using System.Collections.Generic;
using System.Web.Http;
namespace WebApi2Routes1.Controllers
{
// [Controller wird api/Default in diesem Fall genommen, also Controller Name ohne 'Controller'
[RoutePrefix("api/[controller]")]
public class BuecherController : ApiController
{
// GET: api/buecher/default
// [HttpGet]
[Route("")]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET: api/buecher/show
[Route("show")]
public string Show()
{
return "Show";
}
[Route("value/{id:int}")]
public string GetValue(int id)
{
return "value" + id.ToString();
}
}
}
This is my web.config
<?xml version="1.0" encoding="utf-8"?>
<!--
Weitere Informationen zum Konfigurieren Ihrer ASP.NET-Anwendung finden Sie unter
http://go.microsoft.com/fwlink/?LinkId=301879
-->
<configuration>
<appSettings></appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2"/>
<httpRuntime targetFramework="4.5.2"/>
</system.web>
<system.webServer>
<modules>
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
<remove name="OPTIONSVerbHandler"/>
<remove name="TRACEVerbHandler"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs"
type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701"/>
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+"/>
</compilers>
</system.codedom>
</configuration>
I this is the url which throws the error:
http://localhost:8080/api/buecher
and
http://localhost:8080/api/buecher/show
Update 1:
I also have a global.asax
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Routing;
namespace WebApi2Routes1
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}
and a WebApiConfig.cs
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Formatting;
using System.Web.Http;
namespace WebApi2Routes1
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web-API-Konfiguration und -Dienste
// Web-API-Routen
config.MapHttpAttributeRoutes();
// var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
// jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
}

Solved by myself. There where two issues:
[RoutePrefix("api/[controller]")]
[controller] as a token does not work! You have to replace it with a static string like "books" or anything else.
The second issue was that methods need an explicite HHTPGET or HTTPPOST etc. This does not work
[Route("show")]
public string Show()
{
return "Show";
}
This works
[Route("show")]
[HttpGet]
public string show()
{
return "Show";
}
Only if the Method itself is called Get() or Post() or ... then there is no need for [HttpGet].
After replacing the [controller] token in RoutePrefix by a static value and adding [HTTPGET] to the method it worked!

Related

Web API 2 EnableCors not working when I post data with DHC Chrome extension

I am developing a Web API 2 project and I using EnableCors attribute like this:
Controller:
[EnableCors(origins: "http://localhost:32454, http://localhost:25234", headers: "*", methods: "POST")]
WebApiConfig:
config.EnableCors();
Web.config:
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
When I am posting data to my Web API via DHC Chrome extension, my controller is working fine. But, I set two origin. I don't want to access my Web API via DHC. Because, I didn't allow it.
What should I do?
I usually use Owin with Web Api and this should resolve:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
WebApiConfig.Register(config);
ConfigureOAuth(app);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
}

Map to wwwroot in ASP.Net 4?

Is there an easy way to add a subdirectory in ASP.Net v4 Web API that would contain all of my client content? I have read a lot of articles today on virtual paths and routing, but nothing that quite describes this case.
For example, I want to store my images under wwwroot so when the the app receives this request:
http://myapp/img/logo.png
It fetches wwwroot\img\logo.png to handle the request. Obviously, I don't want to have to map out every file or folder individually.
There will be a Web API restful web service that will be handled by the regular routing functionality in WebApiConfig.cs.
(Note: I ask this because I plan to migrate our app to ASP.Net v5 when it is GA, and this would make moving the client-side code trivial)
You can use the Microsoft.Owin.FileSystem and Microsoft.Owin.StaticFiles NuGet Packages to achive what you want.
First add the two NuGet Packages.
Then add this Code to your Startup class:
public void Configuration(IAppBuilder app)
{
// here your other startup code like app.UseWebApi(config); etc.
ConfigureStaticFiles(app);
}
private void ConfigureStaticFiles(IAppBuilder app)
{
string root = AppDomain.CurrentDomain.BaseDirectory;
string wwwroot = Path.Combine(root, "wwwroot");
var fileServerOptions = new FileServerOptions()
{
EnableDefaultFiles = true,
EnableDirectoryBrowsing = false,
RequestPath = new PathString(string.Empty),
FileSystem = new PhysicalFileSystem(wwwroot)
};
fileServerOptions.StaticFileOptions.ServeUnknownFileTypes = true;
app.UseFileServer(fileServerOptions);
}
Also you have to make sure the handler is registered in your Web.config file. It should look like this:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="FormsAuthentication" />
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="Owin" verb="" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb"/>
</handlers>
</system.webServer>
Then every file in your "wwwroot" Folder will be automatically accessible.
For example your wwwroot/img/logo.png file will be accessible via http://yourdomain.com/img/logo.png, just like you want it :)
If you generate the content of the wwwroot folder with npm/gulp/grunt in a build event, then maybe you also have to edit your csproj file and add this ItemGroup:
<ItemGroup>
<Content Include="wwwroot\**\*" />
</ItemGroup>
Add img folder to the root directory of your application. Also you have to to include images in the project or application
For handling file routing I would:
Create HttpHandler as workaround for Image handling/or some other static files.
Bundle config for configuring js and css file path.
Create HttpHandler for handling request to specific file extensions.
And modify the file real path using provided file relative path from the URL.
HttpHandler for .jpg files:
public class ServiceSettings
{
public static string RootStaticFolder = "\\wwwroot";
}
public class ImageHandler : IHttpHandler
{
public bool IsReusable { get { return false; } }
public void ProcessRequest(HttpContext context)
{
var fileSystemPath = context.Server.MapPath(Path.Combine("~") + ServiceSettings.RootStaticFolder);
var file = Path.Combine(Path.GetDirectoryName(context.Request.FilePath), Path.GetFileName(context.Request.FilePath));
var filePath = string.Concat(fileSystemPath, file);
if(!File.Exists(filePath))
{
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
context.Response.Status = "404 Not Found";
}
context.Response.WriteFile(filePath);
}
}
For making it work you must disable MVC routing for this king of files.
RouteConfig.cs:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Disable routing for */*.jpg files
routes.IgnoreRoute("{*alljpg}", new { alljpg = #".*\.jpg(/.*)?" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Then you have to add registration for your HttpHandler to web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="false">
<remove name="FormsAuthentication" />
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="jpgs" verb="*" path="*.jpg" type="WebApplication1.ImageHandler" preCondition="managedHandler"/>
</handlers>
</system.webServer>
Also pay attention to runAllManagedModulesForAllRequests="false" setting in modules tag.
Bundle configuration for css/js files
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/wwwroot/Scripts/jquery-{version}.js"));
// Use the development version of Modernizr to develop with and learn from. Then, when you're
// ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
"~/wwwroot/Scripts/modernizr-*"));
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
"~/wwwroot/Scripts/bootstrap.js",
"~/wwwroot/Scripts/respond.js"));
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/wwwroot/Content/bootstrap.css",
"~/wwwroot/Content/site.css"));
}
With this approach it would be very easy during migration to asp.net 5.
You will only need to remove HttpHandler and bundle configurations.

Implementing Rolling log file in ASP.NET and EntLib 5.0

I am using EntLib 5 to create rolling flat file. This does not use the Rolling Flat File trace listener but the Flat File Trace listener with some modifications in the code.
Rolling Flat File trace listener was not used becuase of issues with it's inherent design as such does not fit the requirement here.
Here is the configuration section:
<configuration>
<configSections>
<section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true"/>
<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
<sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>
<section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
<section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
<section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
</sectionGroup>
</sectionGroup>
</sectionGroup>
</configSections>
<loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
<listeners>
<add name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
fileName="./Logs/MyLog.log" formatter="Text Formatter" />
</listeners>
<formatters>
<add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
template="Timestamp: {timestamp(local)}{newline}
Message: {message}{newline}
Category: {category}{newline}
Priority: {priority}{newline}
EventId: {eventid}{newline}
Severity: {severity}{newline}
Title:{title}{newline}
Machine: {localMachine}{newline}
App Domain: {localAppDomain}{newline}
ProcessId: {localProcessId}{newline}
Process Name: {localProcessName}{newline}
Thread Name: {threadName}{newline}
Win32 ThreadId:{win32ThreadId}{newline}
Extended Properties: {dictionary({key} - {value}{newline})}"
name="Text Formatter" />
</formatters>
<categorySources>
<add switchValue="All" name="General">
<listeners>
<add name="Flat File Trace Listener" />
</listeners>
</add>
</categorySources>
<specialSources>
<allEvents switchValue="All" name="All Events" />
<notProcessed switchValue="All" name="Unprocessed Category" />
<errors switchValue="All" name="Logging Errors & Warnings">
<listeners>
<add name="Flat File Trace Listener" />
</listeners>
</errors>
</specialSources>
</loggingConfiguration>
<appSettings>
<add key="LogFolder" value="./Logs"/>
<add key="LogFileName" value="MyLog.log"/>
</appSettings>
<system.web>
Then I create a static class with the following code to configure the logging process:
public static class LoggingHelper {
private static string date = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:yyyyMMdd}", DateTime.Now);
public static void SetLogFile(string logFileFolder,string logFileName) {
if (!string.IsNullOrEmpty(logFileName)) {
string strfileName = logFileFolder + "/" + date + logFileName;
LoggingHelper.SetTraceLogPath(strfileName, "FlatFile TraceListener", "General", "My Login System");
LoggingHelper.WriteLogFile("General", "Log file path " + logFileFolder + "/" + logFileName, " My Login System");
}
}
public static void SetTraceLogPath(string logFile, string logFileName, string category, string message) {
ConfigurationFileMap configFileMap = new ConfigurationFileMap();
configFileMap.MachineConfigFilename = "Web.config";
Configuration entLibConfig = WebConfigurationManager.OpenWebConfiguration("/ASP.NET_Logging");
LoggingSettings loggingSettings = (LoggingSettings)entLibConfig.GetSection(LoggingSettings.SectionName);
FlatFileTraceListenerData data = loggingSettings.TraceListeners.Get("Flat File Trace Listener") as FlatFileTraceListenerData;
data.FileName = logFile;
entLibConfig.Save();
LogEntry objLog = new LogEntry();
objLog.TimeStamp = System.DateTime.Now;
objLog.Categories.Add(category);
objLog.Message = message;
objLog.Priority = 1;
Logger.Write(objLog);
}
public static void WriteLogFile(string category, string msg, string title) {
try {
LogEntry le = new LogEntry();
le.TimeStamp = System.DateTime.Now;
le.Categories.Add(category);
le.Severity = TraceEventType.Information;
le.Priority = 1;
le.Message = msg;
le.Title = title;
le.Priority = 1;
Logger.Write(le);
} catch (LoggingException ex) {
LoggingHelper.WriteLogFile("General", "Error in writing log file " + ex.ToString(), "My Login System");
}
}}
The SetLogFile is called in the Application_Start method is Global.aspx page like so:
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
LoggingHelper.SetLogFile(ConfigurationSettings.AppSettings["LogFolder"].Trim (), ConfigurationSettings.AppSettings["LogFileName"].Trim());
LoggingHelper.WriteLogFile("General", "*** Application_Start ***", "");
}
Then I just call the WriteLogFile method wherever logging is required like so:
protected void btn_Page2_Click(object sender, EventArgs e) {
LoggingHelper.WriteLogFile("General", "btn_Page2_Click on Default.aspx", "");
Response.Redirect("SecongPage.aspx");
}
This works fine but for a minor issue. When the webpage is accessed for the first time it does not create the log file with Logfilename.log format, it just creates MyLog.log or whatever name is specified in Web.config and the log file is created outside the specified folder, in this case 'Log', for the first time. For consequent requests it will create the desired file with the desired filename in the configured folder.
This pattern is repeated on daily basis, the next day for the first request, the log will be written in yesterday's file and from the next request onwards a new file with today's date is created and all the log messages will be written in that file.
What did I do in my code which is causing this to happen?
We use the above code, with minor changes, for logging in our WinForms applications with no issues.
The website is currently not deployed at IIS. Since it's a work in progress, we are using the built-in development server from VS 2008. Another casue of concern is that the code tries to update the Web.config, at leat once, during startup. Don't know if this is the way to go about it!
This is a very simple sample with two pages, the first page has a button when clicked directs to second page. I am trying to have log file implemented on daily basis and the Rolling Flat File that comes with EntLib does not fit the requirement as it will not create a file on daily basis with the required date for that day.
Regards.
after searching for a long time. This is what I came up with. The idea is to use a FlatFile Trace listner instead of the in-build Rolling Flat File.
Disclaimer:
One of my colleagues had this code with him, he does not remember from where he got it, so if you are the owner or have written code similar to this, then thanks to you.
Please don't vote for this answer as I am not the owner of it. Nevertheless it's here to help anyone looking for similar implementation
This uses EntLib 4, but can be used with EntLib 5 as well.
Here is the logging part from my Web.config:
<loggingConfiguration name="Logging Application Block" tracingEnabled="true"
defaultCategory="User" logWarningsWhenNoCategoriesMatch="true">
<listeners>
<add fileName="trace.log" header="----------------------------------------"
footer="----------------------------------------" formatter=""
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
traceOutputOptions="None" filter="All" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="FlatFile TraceListener" />
<add fileName="MyLoggingSystem.log" header="" footer="" formatter="Text Formatter"
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
traceOutputOptions="None" filter="All" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="MyLoggingApp FlatFile TraceListener " />
<add listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.WmiTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
traceOutputOptions="None" filter="All" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.WmiTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="WMI TraceListener" />
</listeners>
<formatters>
<add template="[{timestamp}] [{category}] {message}" type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="Text Formatter" />
</formatters>
<categorySources>
<add switchValue="All" name="Developer">
<listeners>
<add name="FlatFile TraceListener" />
</listeners>
</add>
<add switchValue="All" name="General" />
<add switchValue="All" name="Instrumentation">
<listeners>
<add name="WMI TraceListener" />
</listeners>
</add>
<add switchValue="All" name="EskoLoggingApp">
<listeners>
<add name="MyLogging FlatFile TraceListener " />
</listeners>
</add>
<add switchValue="All" name="User">
<listeners>
<add name="FlatFile TraceListener" />
</listeners>
</add>
</categorySources>
<specialSources>
<allEvents switchValue="All" name="All Events" />
<notProcessed switchValue="All" name="Unprocessed Category" />
<errors switchValue="All" name="Logging Errors & Warnings">
<listeners>
<add name="FlatFile TraceListener" />
</listeners>
</errors>
</specialSources>
</loggingConfiguration>
I have two more sections, file name and folder to save the file:
<appSettings>
<add key="LogFolder" value="./Logs" />
<add key="LogFileName" value="MyLoginSystem" />
</appSettings>
Create a class like so:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using System.Diagnostics;
using System.Globalization;
using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;
using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;
using Microsoft.Practices.EnterpriseLibrary.Logging.Filters;
/// <summary>
/// Summary description for Utility
/// </summary>
public static class Utility {
/// <summary>
/// Instance for log writer
/// </summary>
private static LogWriter writer;
/// <summary>
/// Instance for log writer
/// </summary>
private static LogWriter wmiWriter;
/// <summary>
/// Instance for log writer
/// </summary>
private static LogWriter eskoLoggingWriter;
/// <summary>
/// Intialize the Trace listners without using app.config file
/// </summary>
/// <param name="fileName">log file name</param>
public static void Initialize(string fileName) {
CreateLogWriterFromCode(fileName);
}
/// <summary>
/// Log User Messages
/// </summary>
/// <param name="message">Message text</param>
/// <param name="prior">Logger Priority</param>
/// <param name="traceType">Trave event type</param>
public static void LogUserMessage(string message, int prior, System.Diagnostics.TraceEventType traceType) {
LogEntry(message, "User", prior, traceType);
}
/// <summary>
/// Any type of Log Entry
/// </summary>
/// <param name="message">Message text</param>
/// <param name="category">Logger category</param>
/// <param name="prior">Priory logger </param>
/// <param name="traceType">Trace event type</param>
public static void LogEntry(string message, string category, int prior, System.Diagnostics.TraceEventType traceType) {
try {
LogEntry log = null;
log = new LogEntry();
log.Message = message;
log.Categories.Add(category);
log.Severity = traceType;
log.Priority = prior;
log.TimeStamp = DateTime.Now;
if (writer != null) {
writer.Write(log);
} else {
eskoLoggingWriter.Write(log);
}
// wmiWriter.Write(log);
} catch (LoggingException ex) {
LogEntry(ex.Message, "Developer", prior, traceType);
}
}
/// <summary>
/// Log Developer Messages
/// </summary>
/// <param name="message">Message text</param>
/// <param name="prior">Logger priority</param>
/// <param name="traceType">Trace event type</param>
public static void LogDeveloperMessage(string message, int prior, System.Diagnostics.TraceEventType traceType) {
LogEntry(message, "Developer", prior, traceType);
}
/// <summary>
/// Close splash screen
/// </summary>
public static void ExitSplash() {
Logger.Reset();
}
/// <summary>
/// Disposing log write instance
/// </summary>
public static void Dispose() {
if (writer != null) {
writer = null;
}
}
/// <summary>
/// Creating log writer programatically
/// </summary>
/// <param name="fileName">Full path of log file</param>
static private void CreateLogWriterFromCode(string fileName) {
if (writer != null) {
writer = null;
}
//// The formatter is responsible for the look of the message. Notice the tokens: {timestamp}, {newline}, {message}, {category}
TextFormatter formatter = new TextFormatter
("[{timestamp}]" + "[{category}]" + "{message}{newline}");
//// Log messages to a log file. Use the formatter mentioned above specified.
FlatFileTraceListener logFileListener = new FlatFileTraceListener(fileName, "", "", formatter);
//// My collection of TraceListeners.
LogSource mainLogSource =
new LogSource("FlatFile TraceListener", SourceLevels.All);
mainLogSource.Listeners.Add(logFileListener);
//// Assigning a non-existant LogSource for Logging Application Block
//// Specials Sources I don't care about.Used to say "don't log".
LogSource nonExistantLogSource = new LogSource("Empty");
//// I want all messages with a category of "User" or "Developer" to get distributed
//// to all TraceListeners in my mainLogSource.
IDictionary<string, LogSource> traceSources =
new Dictionary<string, LogSource>();
traceSources.Add("User", mainLogSource);
traceSources.Add("Developer", mainLogSource);
// Let's glue it all together.
// No filters at this time.
// I won't log a couple of the Special
// Sources: All Events and Events not
// using "Error" or "Debug" categories.
writer = new LogWriter(new ILogFilter[0],
traceSources,
nonExistantLogSource,
nonExistantLogSource,
mainLogSource,
"ALL",
false,
true);
}
/// <summary>
/// Creating log writer programatically
/// </summary>
static public void CreateLogWriterFromCode(string folder, string fileName) {
if (eskoLoggingWriter == null) {
//// The formatter is responsible for the look of the message. Notice the tokens: {timestamp}, {newline}, {message}, {category}
TextFormatter formatter = new TextFormatter
("[{timestamp}]" + "[{category}]" + "{message}{newline}");
//// Log messages to a log file. Use the formatter mentioned above specified.
string date = String.Format("{0:yyyyMMdd}", DateTime.Now);
FlatFileTraceListener logFileListener = new FlatFileTraceListener(folder + "/" + fileName + "_" + date + ".log", "", "", formatter);
WmiTraceListener wmiListener = new WmiTraceListener();
//// My collection of TraceListeners.
LogSource mainLogSource =
new LogSource("FlatFile TraceListener", SourceLevels.All);
LogSource wmiMainLogSource = new LogSource("WmiTraceListener", SourceLevels.All);
mainLogSource.Listeners.Add(logFileListener);
wmiMainLogSource.Listeners.Add(wmiListener);
//// Assigning a non-existant LogSource for Logging Application Block
//// Specials Sources I don't care about.Used to say "don't log".
LogSource nonExistantLogSource = new LogSource("Empty");
//// I want all messages with a category of "User" or "Developer" to get distributed
//// to all TraceListeners in my mainLogSource.
IDictionary<string, LogSource> traceSources =
new Dictionary<string, LogSource>();
traceSources.Add("User", mainLogSource);
traceSources.Add("Developer", mainLogSource);
IDictionary<string, LogSource> wmiTraceSources =
new Dictionary<string, LogSource>();
wmiTraceSources.Add("Instrumentation", wmiMainLogSource);
// Let's glue it all together.
// No filters at this time.
// I won't log a couple of the Special
// Sources: All Events and Events not
// using "Error" or "Debug" categories.
eskoLoggingWriter = new LogWriter(new ILogFilter[0],
traceSources,
nonExistantLogSource,
nonExistantLogSource,
mainLogSource,
"ALL",
false,
true);
wmiWriter = new LogWriter(new ILogFilter[0],
wmiTraceSources,
nonExistantLogSource,
nonExistantLogSource,
wmiMainLogSource,
"All",
true,
true);
}
}
}
In Global.asax, add these line in Application_Start
void Application_Start(object sender, EventArgs e) {
// Code that runs on application startup
Utility.CreateLogWriterFromCode(ConfigurationSettings.AppSettings["LogFolder"].Trim(), ConfigurationSettings.AppSettings["LogFileName"].Trim());
Utility.LogUserMessage("******** Application_Start Event My Login application started ******", 1, System.Diagnostics.TraceEventType.Information);
}
Now wherver you want to log a message, use
Utility.LogUserMessage
You might have to make minor changes to the Utility class if EntLib 5 is used. That should be trivial.
So there you have, a log file on daily basis with correct data for that day.
Again thank you to the anonymus person who wrote the Utility class in the first place.
Hope this helps.
Regards.

MVC3 Helper Not Working, Not Found

I created the following helper in my main directory under /Helpers:
HtmlHelpers.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace Website.Helpers
{
public static class HtmlHelpers
{
public static MvcHtmlString ActiveActionLinkHelper(this HtmlHelper Html, string text, string action, string controller, string activeClass = "active", bool actionCheck = false)
{
if (Html.ViewContext.RouteData.GetRequiredString("controller") == controller)
{
if (actionCheck)
{
if (Html.ViewContext.RouteData.GetRequiredString("action") == action)
return Html.ActionLink(text, action, controller, new { Class = activeClass });
}
else
{
return Html.ActionLink(text, action, controller, new { Class = activeClass });
}
}
return Html.ActionLink(text, action, controller);
}
}
}
I added the namespace to the Views web.config in my Publishers Areas folder:
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="Website.Helpers" />
</namespaces>
</pages>
</system.web.webPages.razor>
I keep getting this message:
Compiler Error Message: CS1061: 'System.Web.Mvc.HtmlHelper' does not contain a definition for 'ActiveActionLink' and no extension method 'ActiveActionLink' accepting a first argument of type 'System.Web.Mvc.HtmlHelper' could be found (are you missing a using directive or an assembly reference?)
Core: #Html.ActiveActionLink("Dashboard", "Index", "Dashboard")
Does anyone know what I am doing wrong? There are hardly any tutorials on how or where to store an HTML helper. Can someone please advise me?
Core: #Html.ActiveActionLink("Dashboard", "Index", "Dashboard") // here it is the problem
as your method is ActiveActionLinkHelper, your calling different method.
#Html.ActiveActionLinkHelper("Dashboard", "Index", "Dashboard") // try like this.
The compiler is right. You're method is named ActiveActionLinkHelper. Change it to ActiveActionLink and all should be well

Why don't trace listeners log custom handler traffic?

I have a custom handler like this,
public class Handler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
}
public bool IsReusable
{
get
{
return false;
}
}
}
Why does this not work?
<system.diagnostics>
<sources>
<source name="System.Web" switchValue="All" propagateActivity="true">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\logs\Traces_Documents.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
When that is in the web.config it does nothing when I call the handler. No logging etc.
I have previously used the same trace listener on the System.ServiceModel namespace with a WCF service, and that worked.
Do you have tracing enabled?
<system.web>
<trace enabled="true" writeToDiagnosticsTrace="true" />
</system.web>
Also, what version of the framework / IIS are you using?
See the DnrTV episode w/ Steve Smith which has good information on Asp.Net Tracing.

Resources