Website:
The Web Site project is compiled on the fly. You end up with a lot more DLL files, which can be a pain. It also gives problems when you have pages or controls in one directory that need to reference pages and controls in another directory since the other directory may not be compiled into the code yet. Another problem can be in publishing.
If Visual Studio isn't told to re-use the same names constantly, it will come up with new names for the DLL files generated by pages all the time. That can lead to having several close copies of DLL files containing the same class name,
which will generate plenty of errors. The Web Site project was introduced with Visual Studio 2005, but it has turned out not to be popular.
Web Application:
The Web Application Project was created as an add-in and now exists as part
of SP 1 for Visual Studio 2005. The main differences are the Web Application Project
was designed to work similarly to the Web projects that shipped with Visual Studio 2003. It will compile the application into a single DLL file at build
time. To update the project, it must be recompiled and the DLL file
published for changes to occur.
Another nice feature of the Web Application
project is it's much easier to exclude files from the project view. In the
Web Site project, each file that you exclude is renamed with an excluded
keyword in the filename. In the Web Application Project, the project just
keeps track of which files to include/exclude from the project view without
renaming them, making things much tidier.
Reference
The article ASP.NET 2.0 - Web Site vs Web Application project also gives reasons on why to use one and not the other. Here is an excerpt of it:
- You need to migrate large Visual Studio .NET 2003 applications to VS
2005? use the Web Application project.
- You want to open and edit any directory as a Web project without
creating a project file? use Web Site
project.
- You need to add pre-build and post-build steps during compilation?
use Web Application project.
- You need to build a Web application using multiple Web
projects? use the Web Application project.
- You want to generate one assembly for each page? use the Web Site project.
- You prefer dynamic compilation and working on pages without building
entire site on each page view? use Web
Site project.
- You prefer single-page code model to code-behind model? use Web Site
project.
Web Application Projects versus Web Site Projects (MSDN) explains the differences between the web site and web application projects. Also, it discusses the configuration to be made in Visual Studio.
You can use an HTTP module to capture the exception message, stack trace and exception type that is thrown by the web service method.
First some background...
If a web service method throws an exception the HTTP response has a status code of 500.
If custom errors are off then the web
service will return the exception
message and stack trace to the client
as JSON. For example:
{"Message":"Exception
message","StackTrace":" at
WebApplication.HelloService.HelloWorld()
in C:\Projects\Stackoverflow
Examples\WebApplication\WebApplication\HelloService.asmx.cs:line
22","ExceptionType":"System.ApplicationException"}
When custom errors are on then the
web service returns a default message
to the client and removes the stack
trace and exception type:
{"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""}
So what we need to do is set custom errors off for the web service and plug in an HTTP module that:
- Checks if the request is for a web service method
- Checks if an exception was thrown - that is, a status code of 500 is being returned
- If 1) and 2) are true then get the original JSON that would be sent to the client and replace it with the default JSON
The code below is an example of an HTTP module that does this:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
public class ErrorHandlerModule : IHttpModule {
public void Init(HttpApplication context) {
context.PostRequestHandlerExecute += OnPostRequestHandlerExecute;
context.EndRequest += OnEndRequest;
}
static void OnPostRequestHandlerExecute(object sender, EventArgs e) {
HttpApplication context = (HttpApplication) sender;
// TODO: Update with the correct check for your application
if (context.Request.Path.StartsWith("/HelloService.asmx")
&& context.Response.StatusCode == 500) {
context.Response.Filter =
new ErrorHandlerFilter(context.Response.Filter);
context.EndRequest += OnEndRequest;
}
}
static void OnEndRequest(object sender, EventArgs e) {
HttpApplication context = (HttpApplication) sender;
ErrorHandlerFilter errorHandlerFilter =
context.Response.Filter as ErrorHandlerFilter;
if (errorHandlerFilter == null) {
return;
}
string originalContent =
Encoding.UTF8.GetString(
errorHandlerFilter.OriginalBytesWritten.ToArray());
// If customErrors are Off then originalContent will contain JSON with
// the original exception message, stack trace and exception type.
// TODO: log the exception
}
public void Dispose() { }
}
This module uses the following filter to override the content sent to the client and to store the original bytes (which contain the exception message, stack trace and exception type):
public class ErrorHandlerFilter : Stream {
private readonly Stream _responseFilter;
public List OriginalBytesWritten { get; private set; }
private const string Content =
"{\"Message\":\"There was an error processing the request.\"" +
",\"StackTrace\":\"\",\"ExceptionType\":\"\"}";
public ErrorHandlerFilter(Stream responseFilter) {
_responseFilter = responseFilter;
OriginalBytesWritten = new List();
}
public override void Flush() {
byte[] bytes = Encoding.UTF8.GetBytes(Content);
_responseFilter.Write(bytes, 0, bytes.Length);
_responseFilter.Flush();
}
public override long Seek(long offset, SeekOrigin origin) {
return _responseFilter.Seek(offset, origin);
}
public override void SetLength(long value) {
_responseFilter.SetLength(value);
}
public override int Read(byte[] buffer, int offset, int count) {
return _responseFilter.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count) {
for (int i = offset; i < offset + count; i++) {
OriginalBytesWritten.Add(buffer[i]);
}
}
public override bool CanRead {
get { return _responseFilter.CanRead; }
}
public override bool CanSeek {
get { return _responseFilter.CanSeek; }
}
public override bool CanWrite {
get { return _responseFilter.CanWrite; }
}
public override long Length {
get { return _responseFilter.Length; }
}
public override long Position {
get { return _responseFilter.Position; }
set { _responseFilter.Position = value; }
}
}
This method requires custom errors to be switched off for the web services. You would probably want to keep custom errors on for the rest of the application so the web services should be placed in a sub directory. Custom errors can be switched off in that directory only using a web.config that overrides the parent setting.
Best Answer
Use ELMAH - it can capture ajax errors.