I use a separate project for my data layer and call one class within it clsData.cs. I'd like to know which page from the Presentation Layer (in another project within the solution) has referenced it from the clsData side, if that's possible
Use a dedicated library like log4net, or use new StackTrace().GetFrames(), to get a reference to the current stack; that holds all the information you need, including page, method, line numbers etc.
You might want to handle the Application_Error method in your global.asax; as all uncaught exception will route to that method.
Why can't you keep the public properties inside your data access layer,which you can set from the calling class for the logging purpose?
May be you need to first understand the reason behind why you created layers in application. As far as my understanding you want to know what exactly caused a particular error. For that may be you need to think about a different solution instead of logging error in your data layer by accessing the information about the caller.
If we take a case of using the same data layer project in some other solution in different UI layer or may be a console application then would you prefer rewriting the entire data layer again to support logging who is calling your data layer class?
Whenever you make a class library (data layer) I would suggest you do the error logging related to error/exception in that scope only, and throw the error/exception as is to the caller so that the caller can get the correct idea on what happened and caller can take necessary steps.
I'm not sure what your requirement is but it is always advisable to throw the exception to the caller and log at the caller end.
Related
I think this should be fairly simple but I can't find anything on google on this for some reason
I have a WebAPi 2.0 controller (type:ApiController) that can read the read the request headers
Request.Headers.GetValues("SomeHeader");
In the same project I have another class (AccessFactory) that I would like to access the headers from.
Reason being that I would not want to do the same code for every function call to read all the needed headers at the point where they are actually needed.
Within a separate project / DLL you can still get access to the current HTTP context (and thus the request headers) using the System.Web.HttpContext.Current object.
As an aside, I would add that if this DLL is meant to be re-usable across different applications, then consider whether it will be used on non-web applications, and if so you should avoid making dependencies on a web-based context like this. Instead you might consider passing in the header values you need as simple types, or in a custom object. That way they can indicate the context, but a non-web app could pass in equivalent contextual values of its own. But that's a separate design decision depending on the exact purpose and how you intend to use this DLL library in future.
My application has both a UI (ASP.Net) and a WebServices API (WCF) front end that both invoke a single business layer. We use a custom Exception type to communicate errors from the business layer that are safe to display to end users. For example if a user attempts to perform an action that is beyond their credentials the business layer would throw a new FriendlyException("You do not have permission"). The UI layer then handles this exception and shows this message to the end user. If the API made this call then inside the FaultException data would be the "You do not have permission" message.
The problem we have now is we need to start localizing all these messages. The current thinking is to have the BusinessLayer throw static strings ("NO_PERMISSION_ERROR") that would be used by the UI and API handlers to find localized string in their respective resouce files. The only downside to this is our API localization and the UI en-US localization are essentially the same and duplicated. Can we avoid this by using some other pattern or are we on the right track?
Thanks,
J
You are definitely on the right track. You need some identifier (a static string) that need to be resolved to translated message at runtime.
Theoretically you could add something like "getLocalizedMessage(CultureInfo ci)" to your custom exception class, but this doesn't work very well with distributed applications.
Just stick to what you come up already. L10n sometimes requires some redundancy but you can't help it.
How do I implement error handling elegantly? For example, my data access layer can potentially throw 2 types of errors:
1) not authorized access, in which case the page should hide everything and just show the error message
2) errors that inform the user that something like this already exists in the database (say name not unique - for example), and in this case I wouldn't want to hide everything.
EDITED:
As a result of some comments here I devised that I should create derived specialized exception types, such as NotAuthorizedException, DuplicateException, etc etc.... it's all fine and dandy, however I can see 2 problems potentially:
1) Every stored proc has a return field p_error where it contains an error message. Upon getting the data from DB, I need to check this field to see what type of an error has been returned, so I can throw an appropriate exceptions. So, I still need to store my error types/error messages somewhere.....In other words, how do I should the exact message to the user (at certain times I need to) w/o checking the p_error field first. WHich brings me back to error object. Anyone?
2) I can this potentially turning into a nightmare where the number of exceptions equals the number of error message types.
Am I missing something here?
Much thanks to everyone!
You should check out the exception handling block in Enterprise Library. Lots of good tips and codeware surrounding wrapping exceptions and passing them between layers.
Where's your business layer, and why isn't it checking Authorization and integrity? The DAL is too low level to be checking those rules - if you hit a problem there, it's pretty much time to throw an exception. Your business layer or controllers can catch that exception, and display a reasonable message - but it's not something you should regularly be doing.
Create your own exception layer.
DALExceptionManager
DuplicateException
DatabaseException
BLLExceptionManager
NotAuthorizedException
InvalidDateException
In your Presentation Layer, Add this references and create a common exception handler.
In this way you know how to deal with the exception messages.
One option that I was thinking of
using is create an Error class, but
then I would need to pass it from UI
to business layer and the then to data
access layer by reference
I am not sure I understand this. You don't have to pass the error object in every layer. For example, in one of your example, errors that inform the user that something like this already exists in the database (say name not unique - for example) , a sql exception could be thrown by the framework, and you just need to catch the specific exception in your business layer, or UI layer.
Exception handling block by the Enterprise library suggested by other people will allow you define some policy-based exception handling in your web.config file. It could be good place if you want to develop some enterprise application. But for simple application, you may need not go that far.
What happens in the upper layers isn't up to your Data Access Layer. It shouldn't even be aware of what the upper layers are going to do. If you've got a duplicate key error, then it should throw something like a "DuplicateKeyException". If you should hit an authorization error (I presume you mean "exception"), then don't do anything with it - let it bubble back up to the UI layer, which can display an appropriate error page.
Remember that error status values and such things are the reason we invented exceptions.
Enterprise library exception handling block is the bomb as many have pointed out. Using policies you can do things like logging the exception, wrapping it in a different exception, throwing a new exception instead of the original one. Also, if you are looking to perform specific actions based on authentication errors or duplicate record errors etc, you could always create specific derived exception classes and catch those exception types which would precludes the need of passing any objects from the top down. Exceptions should always bubble up not down.
I have two projects, the DLL project which has all my logic and data access stuff, and the ASP.NET project which does my forms etc.
I am a bit confused. I thought if I added the System.Web namespace reference to the DLL project I would be able to reference the Session state information of the ASP.NET page.
I could use each page to get the session info out and pass it to the DLL for the processing but would love to be able to process things directly from the DLL class(s).
Is this possible?
I have fiddled with the System.Web namespace and just seem able to get a reference to the Session variable.
Thanks all.
Jon
As long as the Assembly is loaded in the scope of the Session, it will have access.
Although this type of tight coupling isn't really recommended.
You should be able to use HttpContext.Current.Session
Edit
While yes I agree you should not tightly couple your Business Logic DAL or etc assemblies to ASP.Net session. There are plenty of valid cases for accessing HTTP Context outside of a web project.
Web Controls is probably one of the best examples, reusable HTTP modules, etc..
Now one option, if you want to have your DLL pull the stuff from Session, is to abstract out session. So you could define an interface like IStorage, that your library will know how to use. Then you can have a SessionStorage or MemoryStorage class and use IoC to inject the appropriate class into your library classes. This gives you the freedom to code it how you wanted it to be coded without tying your code to Session. Oh and one other benefit if done properly can be used to not tie your code to the session on the web either.
You can always use HttpContext.Current.Session in your DLL but this is considered as bad practice. A better approach would be to pass the values stored in the session dictionary to your DLL instead of it referencing the session. Another benefit you will gain is that the code in your DLL won't be coupled to the ASP.NET runtime meaning it will be easier to test.
As said by the others, you can always use HttpContext.Current.Session in your DLL, I assume it's your BAL, but you need to be really carefull. What if your DLL is later consumed by a windows service, or some other app that doesn't have an HTTPContext? Whenever I've done this it's always been in a property get method where I wrap the attempt to access HttpContext.Current.Session in a try catch block and if anything goes wrong I repull the needed data from the db.
Do not use HttpContext.Current.Session as your dll will not run always with the Web Application. It may run with any other application like Windows,Console itc.
It is better to use a Method which is actully accept a parameter, which will come form Session Value, if you are using ASP.Net Application, otherwise there will not be any dependency of the application. If your dll project already developed and you are trying to modify the exsiting business logic then no, dont modify your exsiting method, use an Overload method.
i have the following directories:
-UI
-BusinessLogic
-DataAccess
-BusinessObjects
if i have a class that is a client stub to a server side service that changes state on a server system, where would that go . .
this code belongs in the recycle bin ;-)
seriously, if you wrote it and don't know where it goes, then either the code is questionable or your partitioning is questionable; how are we supposed to have more information about your system than you have?
now if you just want some uninformed opinions, those we've got by the petabyte:
it goes in the UI because you said it's a client stub
it goes in the business logic because it implements the effect of a business rule
it goes in the data access layer because it is accessing a state-changing service
it goes in the business object layer because it results in a state change on the server
it would be more helpful if you told us what the stub actually does; without specifics it is hard to know where it belongs, and/or it is easy to argue in a vacuum about where it "should" belong
I would consider this a form of data access, although it's not clear to me that you need to put it in the same project as the rest of your data access classes. Remember that the layers are mainly conceptual -- to help you keep your design clean. Separating them into different projects helps organizationally, but is not mandatory. If it's an actual stub class, then the data access project is probably the natural home for it, but if it's only used in the UI layer, then keeping it there would probably be ok.
I don't think it belongs in any of those. You either need a new directory or a new project entirely. But out of those given, I would have to say BusinessObjects because it's certainly not accessing data according to your description, and rather is simply acting like a local object (stub).
In a web service repository.