Logging for ASP.NET MVC 4: log4net

Logging is always an important part of a software project, tracing errors, passing audits, and allow monitoring etc.

I know how to use log4j in Spring framework, but today I have worked a little on C# MVC 4.

How to easily add logging into ASP.NET MVC 4 code base ?

I use log4net, and you can simply download it from VS NuGet store.

Steps for setting up after installation of log4net package:

1. Open  Global.asax.cs

protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//add
log4net.Config.XmlConfigurator.Configure(new FileInfo(Server.MapPath("~/Web.config")));
 }

2. Open Startup.cs

[assembly: log4net.Config.XmlConfigurator(ConfigFile="Web.config", Watch = true)]

3. Open Web.config

<configuration>
<configSections>
//add
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
//add
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="app-log.txt" />
<appendToFile value="true"/>
<rollingStyle value="Size" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %logger (line:%line) - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="RollingFileAppender" />
</root>
</log4net>
</configuration>

4. Any namespace, say in Controller:

using log4net;
public class AccountController : Controller
{
//add
readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public AccountController()
{
}
private bool try(){ log.Error("Error message"); }
...
}

The only thing missing here is that I have not tried to log Database SQL error. May update this later.

Advertisements

Bypass IdentityManager Popup in ESRI ArcGIS JavaScript API

When using ArcGIS secure layers in JavaScript API 2.5+, the default IdentityManager will come out as a login process for web app users.Please see example at http://developers.arcgis.com/javascript/samples/widget_identitymanager/ What if I already have a login for a web app, and do I need to login again for the map layers? What can be done to avoid the IdentityManager Popup ? Login use ArcGIS REST API: see http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#//02r3000000m5000000 And then bypass the IdentityManager Popup.

//just use AJAX, you can put this login in any page
var timeout = 1440, referer = hostname + '/arcgis/rest';
var postData = {
    'username': username,
    'password': password,
    //'client': 'requestip', //can't work if using this type of request
    'referer': referer,//should be the web app host name
    'expiration': timeout,
    'f': 'json'//,
    //'encrypted': 'true' //if need to enable, please add the necessary js files, see generateToken page source code from ArcGIS
};
//processing data encryption
//postData = encryptFormData(postData, modulus);
$.ajax({
   url: url,//hostname/arcgis/tokens/generateToken
   cache: false,
   type: 'POST',
   dataType: 'jsonp',
   data: postData,
   crossDomain: true,
   success: function (response) {
    //console.log(response);
    if (response) {
        if (response.error) { // access error
         return false;
        } else {
         //store username and token in cookies
         setCookieName("arcgisusername", username, 12);
         setCookieName("arcgistoken", response.token, 12);
        }
     } else {
        return false;
      }
   },
   error: function (error) { // system error
    return false; 
   }
});

//bypass the popup
//require IdentityManager
//now build a identitymanager json object to init the object
var now = +(new Date());
var expires = now + (timeout*60000);
var imObject = {
"serverInfos": [
{
"server": hostname,
"tokenServiceUrl": hostname + "/arcgis/tokens/",
"adminTokenServiceUrl": hostname + "/arcgis/admin/generateToken",
"shortLivedTokenValidity": timeout,
"currentVersion": 10.22,//update necessary
"hasServer": true
}
],
"oAuthInfos": [],
"credentials": [
{
"userId": getCookieName('arcgisusername'),
"server": hostname,
"token": getCookieName('arcgistoken'),
"expires": expires,
"validity": timeout,
"ssl": false,
"creationTime": now,
"scope": "server",
"resources": [
hostname + '/arcgis/rest/services'
]
}
]
};
identityManager.initialize(imObject);

//Please remember that if you need to query some layer data using ajax or using some layer URL,
// you need to manually append the '&token=sometokenfromserver' for the URL

I found another hack to bypass the ArcGIS IdentityManager popup or a new method to access secure layers.

This requires coding in .NET/C#. I figure out that ArcGIS server use request cookie name agstoken as an authentication method for accessing secure layers.So if I can create a login form and post to the Login.aspx and send the response with cookie contains agstoken which I can freely request from ArcGIS services using the REST API.


using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.IO;
using System.Text;
namespace Login
{
    public partial class _Login : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {   
            //code for normal user login, if failed, then redirect to login page
  	    string h = "hostname";
	    //h = Request.UserHostAddress;//may not work as direct ip address
            Response.AddHeader("Access-Control-Allow-Origin","*"); //may tighten the access
            Response.AddHeader("Access-Control-Allow-Methods", "POST");
            Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
	    //cookies
	    HttpCookie c2 = Request.Cookies.Get("agstoken");
	    HttpCookie c3 = Request.Cookies.Get("agsapperror");	
	    string timeout = "1440";//mins
	    string u = Request["u"].ToString();
	    string p = Request["p"].ToString();
	    string referer = h;
	    string tokenURL = h + "/arcgis/tokens/generateToken";
            string type = "application/x-www-form-urlencoded";
            string token = "";
            WebClient wc1 = new WebClient();	
	        try{
	          string loginData = "username="+u+ "&password="+p+     
                       "&f=json&expiration="+timeout+"&encrypted=false&referer="+referer;          
                  wc1.Headers[HttpRequestHeader.ContentType] = type;
	          string loginContent = wc1.UploadString(tokenURL, loginData );
	          //check result      
                  if(loginContent.Contains("error")){
			if(c3 == null){
			     c3 = new HttpCookie("agsapperror");
			     c3.Value  = "userpasswordwrong";
			     c3.Expires = DateTime.Now.AddMinutes(10d);
			     Response.Cookies.Add(c3);
			}
			   Response.Redirect("/");
		               
		   }else{ 
		          //push user token for accessing secure layers
			  token = getUserToken(loginContent);
                          if(c2 == null){
				c2 = new HttpCookie("agstoken");
				c2.Value  = token;
				c2.Expires = DateTime.Now.AddMinutes(1440d);
				Response.Cookies.Add(c2);
			  }
               	         Response.Redirect("/index.html"); 
		   }								   
		   
	       } catch (WebException e1) {
                   //Response.Write("{\"error\":\"network connection error\"}");
		   Response.Redirect("/");
            }
        }
      
	public string getUserToken(string tokens){
	    string token = ""; 
	   if(tokens.Contains("token")){
               string [] r = tokens.Split(new string[]{"\",\""},StringSplitOptions.None);
	       if(r.Length > 0){
                   string part1 = r[0];
                   string [] r2 = part1.Split(new string[]{"\":\""},StringSplitOptions.None);
                   token = r2[1];   
               }
           }
	  return token;
	}
    }
}