MVC3 Helper Not Working, Not Found - asp.net

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

Related

Asp Mvc Model doesnt exist

Hello I am sure this has been asked before but I cannot find the resolution.
The model that gets used
public class TaskList : Base
{
public TaskModel taskModel;
public List<Task> tasks;
public TaskList(string role, int userId) : base(role, userId)
{
taskModel = new TaskModel(userId,role);
}
public void GetTasks(int skip,int take)
{
tasks = taskModel.GetTasks(skip, take);
}
}
The controller
public ActionResult TaskListPartial(int skip, int take)
{
var taskList = new TaskList(role,userId);
taskList.GetTasks(skip, take);
return View(taskList);
}
Web.config compilation part
<system.web>
<compilation>
<assemblies>
<add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>
How do I get the Model to resolve so I can get intellisense?
It show error because in view you have only single model class in namespace and in logic you are going to get value from list of object class.
Please define your view model as:
#model List<wrikeMVCNoAuth.ViewModel.Tasks.TaskList>
I apologise for the mistake I was under the impression that I didnt have to compile the project each time to get the intellisense to display int he views.
Once I had a successful compile everything came back.

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.

How to add custom HTTP headers to asmx call using SoapExtension in c#

I am trying to add a custom HTTP header to the asmx call by intercepting it using the ProcessMessage (SoapMessage message) by extending SoapExtension Class in c#.
The problem here is that all i have in ProcessMessage() is the SoapMessage, while i need to add a custom http header.
I tried doing this :
HttpContext.Current.Request.Headers.Add("X-MyHeader", "xyz");
but it doesn't work.
I resolved this using the following steps:
Build an assembly using the class
namespace HttpWebRequestTest {
public class CustomHttpRequestCreator : IWebRequestCreate
public CustomHttpRequestCreator() { }
public WebRequest Create(Uri uri) {
HttpWebRequest webRequest = Activator.CreateInstance(typeof(HttpWebRequest),
BindingFlags.CreateInstance | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance,
null, new object[] { uri, null }, null) as HttpWebRequest;
webRequest.Headers.Add("MyHeader:MyValue");
return webRequest;
}
}
}
Add the file to GAC and register in web.config
<system.net>
<webRequestModules>
<remove prefix="http:"/>
<remove prefix="https:"/>
<add prefix="http:" type="HttpWebRequestTest.CustomHttpRequestCreator, HttpWebRequestTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2bc4ccb2cdedce53" />
<add prefix="https:" type="HttpWebRequestTest.CustomHttpRequestCreator, HttpWebRequestTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2bc4ccb2cdedce53" />
</webRequestModules>
</system.net>

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.

Friendly URLs for ASP.NET

Python frameworks always provide ways to handle URLs that convey the data of the request in an elegant way, like for example http://somewhere.overtherainbow.com/userid/123424/
I want you to notice the ending path /userid/123424/
How do you do this in ASP.NET?
This example uses ASP.NET Routing to implement friendly URLs.
Examples of the mappings that the application handles are:
http://samplesite/userid/1234 - http://samplesite/users.aspx?userid=1234
http://samplesite/userid/1235 - http://samplesite/users.aspx?userid=1235
This example uses querystrings and avoids any requirement to modify the code on the aspx page.
Step 1 - add the necessary entries to web.config
<system.web>
<compilation debug="true">
<assemblies>
…
<add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</assemblies>
</compilation>
…
<httpModules>
…
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</httpModules>
</system.web>
<system.webServer>
…
<modules>
…
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</modules>
<handlers
…
<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</handlers>
</system.webServer>
Step 2 - add a routing table in global.asax
Define the mapping from the friendly URL to the aspx page, saving the requested userid for later use.
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add("UseridRoute", new Route
(
"userid/{userid}",
new CustomRouteHandler("~/users.aspx")
));
}
Step 3 - implement the route handler
Add the querystring to the current context before the routing takes place.
using System.Web.Compilation;
using System.Web.UI;
using System.Web;
using System.Web.Routing;
public class CustomRouteHandler : IRouteHandler
{
public CustomRouteHandler(string virtualPath)
{
this.VirtualPath = virtualPath;
}
public string VirtualPath { get; private set; }
public IHttpHandler GetHttpHandler(RequestContext
requestContext)
{
// Add the querystring to the URL in the current context
string queryString = "?userid=" + requestContext.RouteData.Values["userid"];
HttpContext.Current.RewritePath(
string.Concat(
VirtualPath,
queryString));
var page = BuildManager.CreateInstanceFromVirtualPath
(VirtualPath, typeof(Page)) as IHttpHandler;
return page;
}
}
Code from users.aspx
The code on the aspx page for reference.
protected void Page_Load(object sender, EventArgs e)
{
string id = Page.Request.QueryString["userid"];
switch (id)
{
case "1234":
lblUserId.Text = id;
lblUserName.Text = "Bill";
break;
case "1235":
lblUserId.Text = id;
lblUserName.Text = "Claire";
break;
case "1236":
lblUserId.Text = id;
lblUserName.Text = "David";
break;
default:
lblUserId.Text = "0000";
lblUserName.Text = "Unknown";
break;
}
This is an alternative example that also uses ASP.NET Routing to implement friendly URLs.
Examples of the mappings that the application handles are:
http://samplesite/userid/1234 - http://samplesite/users.aspx?userid=1234
http://samplesite/userid/1235 - http://samplesite/users.aspx?userid=1235
This example does not use querystrings but requires additional code on the aspx page.
Step 1 - add the necessary entries to web.config
<system.web>
<compilation debug="true">
<assemblies>
…
<add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</assemblies>
</compilation>
…
<httpModules>
…
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</httpModules>
</system.web>
<system.webServer>
…
<modules>
…
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</modules>
<handlers
…
<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</handlers>
</system.webServer>
Step 2 - add a routing table in global.asax
Define the mapping from the friendly URL to the aspx page, saving the requested userid for later use.
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add("UseridRoute", new Route
(
"userid/{userid}",
new CustomRouteHandler("~/users.aspx")
));
}
Step 3 - implement the route handler
Pass the routing context, containing the parameter, to the page. (Note the definition of IRoutablePage)
using System.Web.Compilation;
using System.Web.UI;
using System.Web;
using System.Web.Routing;
public interface IRoutablePage
{
RequestContext RequestContext { set; }
}
public class CustomRouteHandler : IRouteHandler
{
public CustomRouteHandler(string virtualPath)
{
this.VirtualPath = virtualPath;
}
public string VirtualPath { get; private set; }
public IHttpHandler GetHttpHandler(RequestContext
requestContext)
{
var page = BuildManager.CreateInstanceFromVirtualPath
(VirtualPath, typeof(Page)) as IHttpHandler;
if (page != null)
{
var routablePage = page as IRoutablePage;
if (routablePage != null) routablePage.RequestContext = requestContext;
}
return page;
}
}
Step 4 - Retrieve the parameter on the target page
Note the implemetation of IRoutablePage.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Routing;
public partial class users : System.Web.UI.Page, IRoutablePage
{
protected RequestContext requestContext;
protected object RouteValue(string key)
{
return requestContext.RouteData.Values[key];
}
protected void Page_Load(object sender, EventArgs e)
{
string id = RouteValue("userid").ToString();
switch (id)
{
case "1234":
lblUserId.Text = id;
lblUserName.Text = "Bill";
break;
case "1235":
lblUserId.Text = id;
lblUserName.Text = "Claire";
break;
case "1236":
lblUserId.Text = id;
lblUserName.Text = "David";
break;
default:
lblUserId.Text = "0000";
lblUserName.Text = "Unknown";
break;
}
}
#region IRoutablePage Members
public RequestContext RequestContext
{
set { requestContext = value; }
}
#endregion
}
Here's another way of doing it using ASP.NET MVC
First off, here's the controller code with two actions. Index gets a list of users from the model, userid gets an individual user:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace MvcApplication1.Controllers
{
public class UsersController : Controller
{
public ActionResult Index()
{
return View(Models.UserDB.GetUsers());
}
public ActionResult userid(int id)
{
return View(Models.UserDB.GetUser(id));
}
}
}
Here's the Index.asp view, it uses an ActionLink to create links in the correct format:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Index" %>
<%# Import Namespace="MvcApplication1.Controllers" %>
<%# Import Namespace="MvcApplication1.Models" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<div>
<h2>Index of Users</h2>
<ul>
<% foreach (User user in (IEnumerable)ViewData.Model) { %>
<li>
<%= Html.ActionLink(user.name, "userid", new {id = user.id })%>
</li>
<% } %>
</ul>
</div>
</body>
</html>
And here's the userid.aspx view which displays an individual's details:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="userid.aspx.cs" Inherits="MvcApplication1.Views.Users.userid" %>
<%# Import Namespace="MvcApplication1.Controllers" %>
<%# Import Namespace="MvcApplication1.Models" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<div>
<table border ="1">
<tr>
<td>
ID
</td>
<td>
<%=((User)ViewData.Model).id %>
</td>
</tr>
<tr>
<td>
Name
</td>
<td>
<%=((User)ViewData.Model).name %>
</td>
</tr>
</table>
</div>
</body>
</html>
And finally for completeness, here's the model code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplication1.Models
{
public class UserDB
{
private static List<User> users = new List<User>{
new User(){id=12345, name="Bill"},
new User(){id=12346, name="Claire"},
new User(){id=12347, name="David"}
};
public static List<User> GetUsers()
{
return users;
}
public static User GetUser(int id)
{
return users.First(user => user.id == id);
}
}
public class User
{
public int id { get; set; }
public string name { get; set; }
}
}
I've been using a URL rewriter by Intelligencia:
http://urlrewriter.net/
It was so easy to configure - maybe an hour to get it all up and running. Very few problems with it...
I'd recommend it, but I should mentioned I've not tried any other ones.
Good luck!
Also, check out ASP.NET MVC or if you're set on webforms, the new System.Web.Routing namespace in ASP.NET 3.5 SP1
I've developed an open source NuGet library for this problem which implicitly converts EveryMvc/Url to every-mvc/url.
Dashed urls are much more SEO friendly and easier to read. Lowercase URLs tend to create less problems. (More on my blog post)
NuGet Package: https://www.nuget.org/packages/LowercaseDashedRoute/
To install it, simply open the NuGet window in the Visual Studio by right clicking the Project and selecting NuGet Package Manager, and on the "Online" tab type "Lowercase Dashed Route", and it should pop up.
Alternatively, you can run this code in the Package Manager Console:
Install-Package LowercaseDashedRoute
After that you should open App_Start/RouteConfig.cs and comment out existing route.MapRoute(...) call and add this instead:
routes.Add(new LowercaseDashedRoute("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Home", action = "Index", id = UrlParameter.Optional }),
new DashedRouteHandler()
)
);
That's it. All the urls are lowercase, dashed, and converted implicitly without you doing anything more.
Open Source Project Url: https://github.com/AtaS/lowercase-dashed-route

Resources