Exception handling in asp.net mvc view - asp.net-mvc-4

I am handing exception in Controller, and other layers that I have manually added like DataAccess.
I have also placed exception handling in Views.
Is it necessary to do so, or can I remove the exception handling code from view?

This is not necessary, ASP.NET haves exception handling by itself. You only have to throw a exception. The view will catch it automatically when running on 'release' mode
Just add the 'FilterConfig' in your App_start
public class FilterConfig
{
/// <summary>
/// The register global filters.
/// </summary>
/// <param name="filters">
/// The filters.
/// </param>
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}

Related

Implementing IDisposable for WCF service client - Am I doing this right?

I want to safely dispose my WCF client, but I'm not sure if I am implementing IDisposable in the right spot.
I added code to implement IDisposable in the service client inside the Reference.vb file that was created when I added the WCF service as a service reference:
Partial Public Class Service1Client
Inherits System.ServiceModel.ClientBase(Of DataConversionService.IService1)
Implements DataConversionService.IService1, IDisposable
Public Sub New()
MyBase.New
End Sub
'skipping constructors with multiple parameters...
Public Sub Dispose() Implements IDisposable.Dispose
Try
If State <> CommunicationState.Faulted Then
Close()
End If
Finally
If State <> CommunicationState.Closed Then
Abort()
End If
End Try
End Sub
Did I add this in the right spot? When debugging, I wasn't able to hit my breakpoint in the Dispose sub.
Any help is appreciated!
You were close. Firstly, you shouldn't change that Reference.vb file since it will be overwritten when the service definition gets updated and changing that file is not a good practice.
What you can do instead is using Proxy Pattern. The Proxy will be used to call the methods in services and manage the connection state etc. I will write in C# since I don't know VB but you'll get the idea. I will simplify this as much as I can.
The interface of Proxy class might look like this:
public interface IProxy
{
/// <summary>
/// Execute call to service method
/// </summary>
/// <typeparam name="TBusiness">Service interface</typeparam>
/// <typeparam name="TResult">Service method return type</typeparam>
/// <param name="call">Service method</param>
/// <returns>Returns what service method returns</returns>
TResult Execute<TBusiness, TResult>(Func<TBusiness, TResult> call) where TBusiness : class;
/// <summary>
/// Execute call to void service method
/// </summary>
/// <typeparam name="TBusiness">Service Interface</typeparam>
/// <param name="call">Service method</param>
void Execute<TBusiness>(Action<TBusiness> call) where TBusiness : class;
}
As you see, there are two methods in this interface. One of them will be used to call a service method which has a return type, the other one will be used for void methods in the service. You can put non-generic version of these methods to the interface too.
The implementation might be like this:
public class ServiceProxy : IProxy
{
protected void ExecuteCall<TContract>(Action<TContract> code) where TContract : class
{
var contractChannel = default(TContract);
try
{
//Create an instance of service client and call the method
contractChannel = Activator.CreateInstance<TContract>();
code(contractChannel);
((ICommunicationObject)contractChannel).Close();
}
catch (FaultException)
{
((ICommunicationObject)contractChannel).Abort();
}
catch (CommunicationException)
{
((ICommunicationObject)contractChannel).Abort();
}
catch (TimeoutException)
{
((ICommunicationObject)contractChannel).Abort();
}
}
public TResult Execute<TContract, TResult>(Func<TContract, TResult> call) where TContract : class
{
return ExecuteCall(call);
}
public void Execute<TContract>(Action<TContract> call) where TContract : class
{
ExecuteCall(call);
}
}
Then, you can use it like this:
var proxy = new ServiceProxy();
proxy.Execute<Service1Client>(a => a.MethodInTheService());
What's great about this approach and how you can make it perfect is:
You might not want to create the proxy as new ServiceProxy() but inject IProxy as ServiceProxy and use it as WCF client for now but if it changes to Web API in the future e.g., implement and inject WebApiProxy then.
You can use contract interfaces to call the proxy methods.
You can do whatever you want in the proxy class like caching the channels, getting the service endpoints from the database etc.
You don't need to dispose the client. In fact, if you dig deep into the code of ClientBase you'll see how it already implements IDisposable and when it gets disposed it just calls Close() - which has error handling paths to abort if something goes wrong.
Having said this, I would use a pattern similar to the below to close your client channel (you may need to cast to IChannel on Close and Abort):
try
{
client.Close();
}
catch
{
client.Abort();
}

Create a custom Http method

Is it possible to create our own HTTP method by just overriding the HttpMethodAttribute class and specify our own supportedMethods ?
In fact, depending on the case, we need to return the View as complete view with the _Layout, and sometimes we just need to return the PartialView of this view. So my idea is to put an custom attribute, like [HttpPartial] and so the client will tell, depending on the methods used in the request, if it wants the complete view (GET method) or the partial view (PARTIAL method).
Yes, that's possible for APIs. You can look at how the HttpGetAttribute is implemented, and roll your own for a custom method, replacing "get" with "foo":
/// <summary>
/// Identifies an action that supports the HTTP FOO method.
/// </summary>
public class HttpFooAttribute : HttpMethodAttribute
{
private static readonly IEnumerable<string> _supportedMethods = new[] { "FOO" };
/// <summary>
/// Creates a new <see cref="HttpFooAttribute"/>.
/// </summary>
public HttpFooAttribute()
: base(_supportedMethods)
{
}
/// <summary>
/// Creates a new <see cref="HttpFooAttribute"/> with the given route template.
/// </summary>
/// <param name="template">The route template. May not be null.</param>
public HttpFooAttribute(string template)
: base(_supportedMethods, template)
{
if (template == null)
{
throw new ArgumentNullException(nameof(template));
}
}
}
Then apply it to your API action methods:
[Route("Bar")]
public class BarApiController : Controller
{
[HttpFoo("/"]
public IActionResult Foo()
{
return Ok("Foo");
}
}
Now you can request FOO https://your-api:44312/bar/.
This is less useful for actions returning views, as any HTML-rendering user agent only lets the user initiate GET or POST requests through hyperlinks and forms.
You could send more methods through an XMLHttpRequest or fetch(), but it'll require more documentation and client customization.
Don't break or hamper the web, don't invent new HTTP methods for your application logic. Simply use a query string parameter or send it in your body: &renderAsPartial=true, { "renderAsPartial": true }.
See the IANA's Hypertext Transfer Protocol (HTTP) Method Registry for existing methods and see RCF 7231 section 8.1 for how to register new HTTP methods.

Targeting different providers per logger

Is it not possible to target different logging providers based on which logger is used?
For example, refer to the below code:
// Establish loggers
var someLogger = loggerFactory.CreateLogger("SomeLogger");
var anotherLogger = loggerFactory.CreateLogger("AnotherLogger");
// Hook up providers (but not at the individual logger's level??)
loggerFactory.AddDebug(minimumLevel: LogLevel.Debug);
loggerFactory.AddConsole(minimumLevel: LogLevel.Debug);
loggerFactory.AddBlob(connectionString, minimumLevel: LogLevel.Information);
// Log stuff
someLogger.LogError("Logging with someLogger");
anotherLogger.LogError("Logging with anotherLogger");
All providers will be logged too here, regardless of which logger is used.
Is this really not possible? What is the point of defining separate loggers if they all log to every provider regardless?
I'm not sure if that's possible but what you can do is log messages of different log levels to different providers. The example below logs all warning level messages and above to the event log using the SourceSwitch API. The use case here which may satisfy your needs is that you may not want information or debug messages filling up your event log.
private static void ConfigureLogging(ILoggerFactory loggerFactory)
{
var sourceSwitch = new SourceSwitch("EventLog");
sourceSwitch.Level = SourceLevels.Warning;
loggerFactory.AddTraceSource(sourceSwitch, new EventLogTraceListener("Application"));
}
UPDATE
ASP.NET 5 is very light on examples at the moment but the AddProvider method on ILoggerFactory is used to add it's own custom providers specific to it:
/// <summary>
/// Used to create logger instances of the given name.
/// </summary>
public interface ILoggerFactory : IDisposable
{
/// <summary>
/// The minimum level of log messages sent to registered loggers.
/// </summary>
LogLevel MinimumLevel { get; set; }
/// <summary>
/// Creates a new ILogger instance of the given name.
/// </summary>
/// <param name="categoryName"></param>
/// <returns></returns>
ILogger CreateLogger(string categoryName);
void AddProvider(ILoggerProvider provider);
}
So you could create another ILoggerFactory but register different providers to it. Then inject the right ILoggerFactory into your classes depending on where you want to log to.

XBF Error with DataTemplate in Application.Resources

Universal Windows Platform app with Visual Studio 2015 (RTM)
I have a DataTemplate that is used in multiple pages of my app, so I'd prefer to write it once and access it from anywhere I need to. In order to make it accessible by any page, I write it in my App.xaml's <Application.Resources>:
<Application
x:Class="MyApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp"
xmlns:viewmodels="using:MyApp.ViewModels"
RequestedTheme="Light">
<Application.Resources>
<DataTemplate x:Key="DetailContentTemplate" x:DataType="viewmodels:DataViewModel">
...
</DataTemplate>
</Application.Resources>
The DataTemplate portion of the code above works just fine in an individual page, but of course that means I'd have to copy and paste it multiple times to other pages, which just isn't efficient. However, I get this error when I use the DataTemplate in App.xaml:
XBF generation error code 0x09c4
I've determined that it stems from the x:DataType="viewmodels:DataViewModel" (without this, and hence, without any bindings the code works just fine). Looking up the error results in next to nothing. Is there a convenient workaround/solution to being able to reuse a DataTemplate with bindings in a Universal Windows Platform/WinRT app, preferably in XAML?
EDIT: As requested, the code in full for App.xaml.cs:
namespace MyApp
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
sealed partial class App : Application
{
/// <summary>
/// Allows tracking page views, exceptions and other telemetry through the Microsoft Application Insights service.
/// </summary>
public static Microsoft.ApplicationInsights.TelemetryClient TelemetryClient;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
TelemetryClient = new Microsoft.ApplicationInsights.TelemetryClient();
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
// Set the default language
rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
rootFrame.NavigationFailed += OnNavigationFailed;
if (rootFrame.Content == null)
{
rootFrame.Navigate(typeof(MasterDetailPage));
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
// Ensure the current window is active
Window.Current.Activate();
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
deferral.Complete();
}
}
}
You can find some explanation here from the latest build session at 20:10
You basically need to create a resource dictionary in XAML and attach a class to it. This class file is needed to allow the compiler to generate its code.
Depending on what you have to do and how you can change your code, you can still use the "old" {Binding} markup which will work as before.
<Application.Resources>
<DataTemplate x:Key="DetailContentTemplate">
<TextBlock Text={Binding myValue} />
</DataTemplate>
</Application.Resources>

WCF Data Service - Restrict visibility and logging queries

I have two questions related to WCF Data Service:
is there a way to restrict the entities visible to a user according to her privileges ? For instance user in role super-user should be able to query the full 'Contact' entity but user with less privileges would only be able to see specific properties of the 'Contact' entity.
whenever a user runs a query on the service, I would like this to be logged in a database for audit purpose. Is this possible ?
1) There is the concept of interceptors: http://msdn.microsoft.com/en-us/library/dd744842.aspx
But I think they won't satisfy you in your case:
With change interceptors you can handle requests which try to change a specific entity. This could help you to avoid users without certain privileges to add/change/delete contact entities. With QueryInterceptors you can handle GET-Requests. But they don't allow you to restrict certain properties of your contact entity.
You are not the first with such requirements -> WCF Dataservice - modify object before returning results?
Maybe you could use a combination of a (custom) ServiceOperation and a View to handle this.
2) Yes, you can do this for instance by handling the ProcessingRequest-Event:
public class YourService : DataService<Entities>
{
/// <summary>
/// The logger.
/// </summary>
private readonly LogWriter logger;
/// <summary>
/// Initializes a new instance of the <see cref="YourService"/> class.
/// </summary>
public YourService()
{
this.logger = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
this.ProcessingPipeline.ProcessingRequest += this.ProcessingPipelineProcessingRequest;
}
/// <summary>
/// OnProcessingRequest
/// </summary>
/// <param name="sender">source</param>
/// <param name="e">event args</param>
public void ProcessingPipelineProcessingRequest(object sender, DataServiceProcessingPipelineEventArgs e)
{
this.logger.Write(new LogEntry { Message = "SOP ProcessingPipelineProcessingRequest: Unauthorized Access", Severity = TraceEventType.Warning })
}
}
You can find all those ProcessingPipeline-Events here: http://msdn.microsoft.com/en-us/library/system.data.services.dataserviceprocessingpipeline(v=vs.103).aspx