Custom Exception with Entity Framework and Repository Pattern - asp.net

I am following this Asp .Net tutorial as a guide:
http://www.asp.net/web-forms/tutorials/continuing-with-ef/using-the-entity-framework-and-the-objectdatasource-control-part-2-adding-a-business-logic-layer-and-unit-tests
I have created a custom error to prevent duplicate records on insert and update
Public Class DuplicateAgencyException
Inherits Exception
Public Sub New(ByVal message As String)
MyBase.New(message)
End Sub
End Class
I have created a validation method that checks for duplication on insert or update:
Public Sub ValidateAgencyName(ByVal agency As agency_temp)
If Not IsNothing(agency) Then
Dim duplicateAgency As agency_temp = AgencyRepository.GetAgencyByName(agency.agency_name).FirstOrDefault()
If Not IsNothing(duplicateAgency) AndAlso duplicateAgency.agency_id <> agency.agency_id Then
Throw New DuplicateAgencyException(String.Format("Agency: {0} already exists.", duplicateAgency.agency_name))
End If
End If
End Sub
I run a unit test to insert a record, and purposefully insert a duplicate, and it throws the correct error. Now I need to handle this error with the ObjectDataSource that displays this data, such as OnInserted and OnUpdated, but I can't even get to that point. When I insert a record, I get the error assistant telling me that DuplicateAgencyException was unhandled by user code. Do I need a try...Catch there? (I did try that to no avail).

I believe you need to wrap your exception within the methods referenced by the events you mention in a try catch block as you suggest. You should wrap the existing code like so
MethodName(params)
《
try 《 /// existing code
》
catch (ExceptionType ex) 《
/// error handling code
》
》
If you post your event handling code and the aspx i can be more specific. Please excuse any errots wrote this on my phone.

Related

Website - The type initializer for 'Static Class' threw an exception

I have a VB.NET website project. In one of the pages, during a button click, it is supposed to load a telerik RadGrid with data. It works fine on my local machine. However when I deploy it to pre-production on a server, it throws the following error.
The type initializer for 'Utility' threw an exception
Utility is a Static class and while calling any members of the static class (either public static functions or public static variables) I was receiving this error.
Here is the code snippet:
Partial Class Session
Inherits System.Web.UI.Page
Protected Sub RadGrid1_ItemDataBound(sender As Object, e As Telerik.Web.UI.GridItemEventArgs) Handles RadGrid1.ItemDataBound
If TypeOf e.Item Is GridDataItem Then
Dim testString As String = String.Empty
Dim encryptString As String = String.Empty
Try
encryptString = Utility.EncryptString(cellValue.ToString())
testString = Utility.test
Catch ex As Exception
Logger.getInstance().log("Value1" & cellValue.ToString() & "Value2" & testString)
Finally
End Try
End If
End Sub
End Class
In my Utility.vb, this is what I have:
Public Class Utility
Public Shared test As String = "hello"
Public Shared Function EncryptString(ByVal strEncrypted As String) As String
Try
Dim b As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(strEncrypted)
Dim encryptedConnectionString As String = Convert.ToBase64String(b)
Return encryptedConnectionString
Catch ex As Exception
Logger.getInstance().log("Error occurred in Utility.vb while executing EncryptString method. \nSOURCE: " & ex.Source.ToString() & "\nMESSAGE: " & ex.Message.ToString() & "\nTARGETSITE: " & ex.TargetSite.ToString() & "\nSTACKTRACE: " & ex.StackTrace.ToString())
Logger.getInstance().log("\nstrEncrypted: " & strEncrypted)
Finally
End Try
End Function
End Class
From my logging statements, I realized that the error is happening right when I call the Utility class because none of the logging statements I added into the EncryptString() function are being shown in my logs.
I tried commenting out the code for EncryptString() function and added just a public static string variable called test in my Utility class, and tried accessing it from my code from Session.aspx.vb. That string value was not being returned as well.
By the way, all of my code is in the same website project. The error is driving me crazy for past 2 days. Like I mentioned, it works fine on my local machine, but fails only on the pre-prod server. The code was written using an older framework (3.5 I believe) and then we upgraded to 4.6.2 and migrating to new servers. We are facing this issue during the migration process on the new server.
OK, so I figured out the issue. At the beginning of the Utility.vb class there were some unsupported cryptographic algorithm variable declarations.
Private Shared DES As New TripleDESCryptoServiceProvider
Private Shared MD5 As New MD5CryptoServiceProvider
FIPS compliance is turned on, on the server and we already knew these algorithms were non-compliant with the latest .net frameworks. But I didn't realize even just these declarations would throw a misleading error, when they were not really being used in my function calls.
When I commented out those parts of the code, it started working fine.
Check the InnerException property of the exception. Any time a class initializer fails the original exception should be set as the InnerException property of the unhandled exception.
If you want a truly static class, you need to make it a module, in VB.Net.

ASP.NET web service returns 400

If I de-serialize the data and an error occurs later in the update process (for example: the change fails to meet a database constraint). I'd like to report something useful to the end user here, but it looks like .NET is swallowing the error. Any idea why?
<WebInvoke(method:="POST", uriTemplate:="changes", bodyStyle:=WebMessageBodyStyle.Bare)>
Public Function PostChanges(body As Stream) As String
Try
' This returns 500 Server Error (with wrapped exception)
'Throw New Exception("TEST")
Dim data As String = ""
Using reader As New StreamReader(body)
data = reader.ReadToEnd()
End Using
' This returns 400 Bad Request
'Throw New Exception("TEST")
' Code handling data removed (no error if exceptions are removed)
Catch ex As Exception
Throw New WebFaultException(Of DisplayError)(New DisplayError(ex.Message, ex.StackTrace), Net.HttpStatusCode.InternalServerError)
End Try
Apparently, StreamReader disposes of its underlying Stream object which causes problem if your code has the temerity to break normal flow by raising an exception.
So, now I'm using OperationContext.Current.RequestContext.RequestMessage.ToString, which has its own problems but at least I'm not choosing between messed up error logging or a resource leak.

Instantiating a class within WCF

I'm writing a WCF WebMethod to upload files to, of which I taken snippets from around the web. The WCF interface looks like this:
<ServiceContract()>
Public Interface ITransferService
<OperationContract()>
Sub UploadFile(ByVal request As RemoteFileInfo)
End Interface
<MessageContract()>
Public Class RemoteFileInfo
Implements IDisposable
<MessageHeader(MustUnderstand:=True)>
Public FileName As String
<MessageHeader(MustUnderstand:=True)>
Public Length As Long
<MessageBodyMember(Order:=1)>
Public FileByteStream As System.IO.Stream
Public Sub Dispose() Implements IDisposable.Dispose
If FileByteStream IsNot Nothing Then
FileByteStream.Close()
FileByteStream = Nothing
End If
End Sub
End Class
Within ASP.NET, when the web method is consumed, for some reason it only works when the interface is used as part of the instantiation of RemoteFileInfo:
Protected Sub btn_Click(sender As Object, e As EventArgs) Handles btn.Click
If fu.HasFile Then
Dim fi As New System.IO.FileInfo(fu.PostedFile.FileName)
' this is the line in question --------------
Dim cu As ServiceReference1.ITransferService = New ServiceReference1.TransferServiceClient()
' -------------------------------------------
Dim uri As New ServiceReference1.RemoteFileInfo()
Using stream As New System.IO.FileStream(fu.PostedFile.FileName, IO.FileMode.Open, IO.FileAccess.Read)
uri.FileName = fu.FileName
uri.Length = fi.Length
uri.FileByteStream = stream
cu.UploadFile(uri)
End Using
End If
End Sub
Can anyone advise why it is not possible to create an instance of TransferService using the following approach:
Dim cu As New ServiceReference1.TransferServiceClient()
If I try the above, it breaks this line:
cu.UploadFile(uri)
...and UploadFile must be called with three parameters (FileName, Length, FileByteStream) even there is no method that uses this signature.
Why is the Interface required when creating an instance of this class please?
When you create the proxy for your service with the "Add Service Reference" dialog, by default the proxy creation code will "unwrap" message contracts, like the one you have. If you want the message contract to appear as you defined on the server side on your proxy, you need to select the "Advanced" tab, and check the "Always generate message contracts" option. With that you'll get the message contract in your client as well.
The issue is that when a MessageContract is encountered as a parameter, the WCF client generation assumes by default that you want to implement a messaging-style interface, and provides the discrete properties from the message contract as part of the client-side interface.
The Using Messaging Contracts article in MSDN contains a very detailed description of what can be done with a messaging contract and I suspect that Microsoft chose this default behavior because of some of the "games" that you can play with the messages.
However, if you examine the code generated for your UploadFile on the client side, there are some interesting tidbits that help to explain what is going on.
The first is the comments for the UploadFile method in the interface:
'CODEGEN: Generating message contract since the operation UploadFile is neither RPC nor document wrapped.
...
Function UploadFile(ByVal request As ServiceReference1.RemoteFileInfo) As ServiceReference1.UploadFileResponse
This implies that the contract would have been generated differently if the message contract had a different implementation.
The second is that you will see that there is nothing special about the code that is used to actually make the service call:
Public Sub UploadFile(ByVal FileName As String, ByVal Length As Long, ByVal FileByteStream As System.IO.Stream)
Dim inValue As ServiceReference1.RemoteFileInfo = New ServiceReference1.RemoteFileInfo()
inValue.FileName = FileName
inValue.Length = Length
inValue.FileByteStream = FileByteStream
Dim retVal As ServiceReference1.UploadFileResponse = CType(Me,ServiceReference1.ITransferService).UploadFile(inValue)
End Sub
So in this case, your code is doing exactly what the generated code does. However, if the MessageContract were more complex, I suspect that this would no longer be the case.
So, for your question:
Can anyone advise why it is not possible to create an instance of
TransferService using the following approach...
There is no reason not to take this approach as long as you verify that the implementation of the method call is functionality equivalent to your code.
There are a couple of options for changing the default generation of the method in the client:
1) Remove the MessageContract attribute from the RemoteFileInfo class.
2) Although it seems to be counter-intuitive, you can check the Always generate message contracts checkbox in the Configure Service Reference Dialog Box.

How to customize InnerException.Message for System.Data.UpdateException in ASP.NET

First of all thanks for taking the time to read through my post. I have a question that may be a newbie piece of cake for some.
I am adding data to a database table using Entity Framework. When adding a duplicate Primary Key I get an exception in InnerException.Message that reads "Violation of PRIMARY KEY constraint 'PK_StudentID'. Cannot insert duplicate key in object 'dbo.Students'. The statement has been terminated. "
However, what I want to do is to rephrase this error message for the end user, but also save this exact message with the table name and column name to my logs for later. Essentially, I want to rephrase the error message to "You cannot have a duplicate entry for Student Identification Number. Please enter a new value."
How can I do this?
I have tried to inherit from System.Data.UpdateException and put an if check to see what the innerexception.message reads, and then change it accordingly. That did not work.
Thanks,
I think this will do what you want.
Try
'your code
Catch ex As Exception
'store the ex.Message where you want
Throw New Exception("Your custom message here.")
End Try
Example:
Private Sub uiFunction()
Dim errorMessage As String
Try
'a call to a BLL function/sub that could cause an exception
Catch ex As Exception
errorMessage = ex.Message() 'ex.Message() = "Your custom message."
End Try
End Sub
Public Sub BLLFunction()
Try
'run your code that could cause an exception
Catch ex As Exception
Throw New Exception("Your custom message.")
End Try
End Sub

ASP.NET: Very simple event handling not working

I have an object Order with a simple event,
Public Event ErrorOccurred(ByVal msg As String)
that I raise in the constructor like so when an order cannot be found (along w/setting a boolean error flag:
RaiseEvent ErrorOccurred("This order does not exist in the database.")
[Error] = True
I have a webform subscribed to the order's ErrorOccurred event:
Public WithEvents o As New Order
and I have an error handler method on the form:
Private Sub OnErrorOccurred(ByVal msg As String) Handles o.ErrorOccurred
litMsg.Text = "<p class=""error-confirm"">" & msg & "</p>"
End Sub
When a textbox is changed, it autoposts back to the page and employs the following logic:
Private Sub txtOrderID_TextChanged(ByVal sender As Object,_
ByVal e As System.EventArgs) Handles txtOrderID.TextChanged
If IsNumeric(txtOrderID.Text) Then
If o.OrderID = 0 Then o = New Order(txtOrderID.Text)
If Not o.Error Then
'do stuff'
Else
'error, run error handling'
End If
....
When there is an error (when the Else logic is run), everything performs as expected except the event does not fire. However, since the Error flag is set to true, it means the event MUST have fired, since that line executes AFTER the RaiseEvent line.
I've tried everything I can think of, but I cannot figure out what could be wrong. I have events strewn everywhere in my project and they all work well using virtually the same structure. What could I be doing wrong here?
I would say that since you are raising the event in the constructor, before you even have a reference to the object in your parent class, that you are unable to handle the event. In this case, especially with errors in the constructor, you would probably be much better off throwing an exception than to raise an event. I would be better to throw an exception, because some other code calling your class might not even handle the event, and you would most likely want to know that an error occured. Throwing exceptions is the standard way of letting the calling code know that an error occured. Events are more for optional things that the calling class may want to handle, but that it may also want to ignore.

Resources