CRM 2013 Exception Handling due to Security Roles - c#

I have a plugin which fires on Update of the Incident entity. It creates a new record in another table (new_documentaccess). This new_documentaccess record needs to have the same Owner as that of the Incident entity.
Now, I understand that I cannot set the Owner field like any other field on the entity by doing a simple assignment.
So, I wrote in the following.
public void CreateDocumentAccess(Incident incident)
{
new_documentsaccess documentAccess = new new_documentsaccess();
documentAccess.new_CaseId = incident.ToEntityReference();
documentAccess.new_name = incident.OwnerId.Name;
Guid recordId = crmService.Create(documentAccess);
var request = new AssignRequest{
Assignee = new EntityReference(SystemUser.EntityLogicalName, incident.OwnerId.Id),
Target = new EntityReference(new_documentsaccess.EntityLogicalName, recordId)};
crmService.Execute(request);
}
However, I got the following error during execution when I was debugging with
Break when an exception is Thrown: enabled for Common Language Runtime Exceptions.
thrown at the line
var request = new AssignRequest{
Assignee = new EntityReference(SystemUser.EntityLogicalName, incident.OwnerId.Id),
Target = new EntityReference(new_documentsaccess.EntityLogicalName, recordId)};
Principal user (Id=e9e3a98d-a93e-e411-80bc-000c2908bc67, type=8) is
missing prvAssignnew_documentsaccess privilege
(Id=7ecaf3da-77c8-4ee3-9b29-e5a4455cd952)"}
My Plugin code is as follows
try
{
CreateDocumentAccess(Incident incident);
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred while creating the document access.", ex);
}
catch (Exception ex)
{
TracingService.Trace("ExecutePreIncidentUpdate: {0}", ex.ToString());
throw;
}
If I just run it as User using the front end, I get the following error.
Exiting PluginPreIncidentUpdate.Execute(), Correlation Id: 4e7e4c3c-3cef-46ab-8d08-a6d0dbca34c7, Initiating User: be179876-9b39-e411-80bb-000c2908bc67
Questions
What code changes should I be making so that even if it errors out
on the above mentioned error, the ErrorDetails.txt captures the
error Principal user (Id=e9e3a98d-a93e-e411-80bc-000c2908bc67, type=8) is missing prvAssignnew_documentsaccess privilege
(Id=7ecaf3da-77c8-4ee3-9b29-e5a4455cd952)?
Why is it not happening already?

Firstly: To answer your questions:
Trace logs are only included with InvalidPluginExecutionException. Your second catch is being used and is throwing the caught exception not an "InvalidPluginExecutionException"
Changing this:
catch (Exception ex)
{
TracingService.Trace("ExecutePreIncidentUpdate: {0}", ex.ToString());
throw;
}
To something like this should pull your trace logs through into the ErrorDetails attachment.
catch (Exception ex)
{
TracingService.Trace("ExecutePreIncidentUpdate: {0}", ex.ToString());
throw new InvalidPluginExecutionException("An error has occurred");
}
Secondly: The cause
The error you are getting is indicating that the user does not have privileges to assign a new_documentaccess record.
When you register a plugin and add a new step; you can choose which user's context to run it in.
By default this is set to "Calling User".
Can you confirm that the calling user is in a security role that has the assign privilege for new_documentaccess records?

Related

How to get user defined SQLException number with Dapper

My stored procedure is throwing custom errors to handle validation within a multi user web app. This is working as expected in SQL Server with error number 50001 being returned however when my C# code catches the error it always has the error number 50000 instead of 50001 therefore I cannot treat the errors differently.
How can I catch error number 50001? Note that I am using Dapper to execute all stored procedures.
SQL
THROW 50001, 'Client already has an Active Visit! THIS IS DEV!!!!',1;
Msg 50001, Level 16, State 1, Line 1
Client already has an Active Visit! THIS IS DEV!!!!
C#
catch (SqlException ex)
{
var errorHandler = new ErrorHandler();
var msg = errorHandler.ErrorMessage(ex);
if (ex.Number == 50001)
{
return BadRequest(msg);
}
else
{
return StatusCode(500, msg);
}
}
catch (Exception ex)
{
var errorHandler = new ErrorHandler();
return StatusCode(500, errorHandler.ErrorMessage(ex));
}
EXAMPLE
SQL server error 50000 is reserved for general user defined message, so it sounds like it's not finding error 50001 in sys.messages. You can try to add the error using the stored procedure sp_addmessage.
Once that is done, you can call it like this:
RAISERROR(50001, 1, 1)
Another reason it could be error 50000 is if you are raising the SQL error in a SQL TRY/CATCH as that will always return a 50000 error code.
Just tried this code myself:
using (var cmd = new SqlCommand("THROW 50001,'error',1;", conn))
{
cmd.ExecuteNonQuery();
}
And that does return ex.Number 50001 so it must be a problem in your SQL. Like I said above, it could be caused by a TRY/CATCH as this won't save the original error code number.

EF EntityState.Modified Try Catch Issue

I have a code like this:
try
{
Member member = database.Members.Where(m=>m.ID=1).FirstOrDefault();
member.Name = "NewMemberName";
database.Entry(member).State = EntityState.Modified;
database.SaveChanges();
}
catch (Exception ex)
{
database.Logs.Add(new Log() { Value=ex.ToString() });
database.SaveChanges();
}
And Entity:
[StringLength(5)]
public string Name { get; set; }
If the Name String more than 5 it would be error and catch the exception ,but when I add a log then save ,the exception from SaveChange(); still remains,how should I do?(Can't change the schema)
the exception from SaveChange(); still remains
Well, if this throws an exception:
database.SaveChanges();
Then there's a pretty good chance that this will also throw an exception:
database.SaveChanges();
Basically, in your catch block you shouldn't be immediately re-trying the operation that just failed a millisecond ago. Instead, log the failure and handle the exception:
catch (Exception ex)
{
// DO NOT call SaveChanges() here.
}
Of course, if writing to the database is failing, then logging to the database is also likely to fail. Suppose for example that the connection string is wrong or the database is down or timing out. You can't log that.
I recommend using a logging framework (log4net, NLog, etc.) as a separate dependency from your Entity Framework data access layer. It's a small learning curve, but you end up with a pretty robust logging system that can much more effectively handle problems. And can be easily configured to log to multiple places, so if writing to one error log (the database) fails then you still have another one (a file, for example).
At the very least, if persisting your data context fails, you'll need to log to a new data context. Otherwise the part that failed is still there.
Something structurally more like this:
try
{
using (var database = new DbContext())
{
Member member = database.Members.Where(m=>m.ID=1).FirstOrDefault();
member.Name = "NewMemberName";
database.Entry(member).State = EntityState.Modified;
database.SaveChanges();
}
}
catch (Exception ex)
{
using (var database = new DbContext())
{
database.Logs.Add(new Log() { Value=ex.ToString() });
database.SaveChanges();
}
}

Is multiple try-catch in error sensitive code considered a good practice?

I have a code segment that is responsible for orchestrating the execution of a few modules and it is very sensitive to errors - I want to make sure I log and alert about every exception that occurs.
Right now I have something like this:
try
{
ModuleAResult aResult = ModuleA.DoSomethingA();
}
catch (Exception ex)
{
string errorMessage = string.Format("Module A failed doing it's thing. Specific exception: {0}", ex.Message);
// Log exception, send alerts, etc.
}
try
{
ModuleBResult bResult = ModuleB.DoSomethingB();
}
catch (Exception ex)
{
string errorMessage = string.Format("Module B failed doing it's thing. Specific exception: {0}", ex.Message);
// Log exception, send alerts, etc.
}
// etc for other modules.
It looks to me that the multiple try-catch is making this segment less readable. Is it indeed the right thing to do?
Yes, it's the right thing.
But you should have the performance in in mind, maybe it's better to put all method calls in one try/catch and add stack trace and error information in the exception in the methiod itself.
public void ModuleA.DoSomethingA()
{
throw new Exception("Error in module A");
}
try
{
ModuleAResult aResult = ModuleA.DoSomethingA();
ModuleBResult bResult = ModuleB.DoSomethingB();
}
catch (Exception ex)
{
// get information about exception in the error message
}
You did well.
This way, you can process the error after each module. If you want to run it all and then do error handling, consider this alternative:
try
{
ModuleAResult aResult = ModuleA.DoSomethingA();
ModuleBResult bResult = ModuleB.DoSomethingB();
}
catch(ModuleAException ex)
{
// handle specific error
}
catch(ModuleBException ex)
{
// handle other specific error
}
catch (Exception ex)
{
// handle all other errors, do logging, etc.
}
i think that depends on the approach that you want to follow.
It seems like you error messsages are different for each module that raises exception so i guess the approach that you followed is right.
you could have put the whole thing in a big try - catch block then in that case you will not know which module caused the exception as a generic excpetion gets printed.
try
{
ModuleAResult aResult = ModuleA.DoSomethingA();
ModuleBResult bResult = ModuleB.DoSomethingB();
}
catch (Exception ex)
{
string errorMessage = string.Format("Either Module A or B failed", ex.Message);
// Log exception, send alerts, etc.
}
So if you want your exception handling to not be cleaner use the above code.
Otherwise what you followed is absolutely fine.

C# oracle : catch all exceptions relative to connectivity?

In c#, can I catch all errors about (non) connectivity to an Oracle database?
I don't want to catch error about badly written query but only errors like No listener, connection lost...
If queries are badly written (or table are missing) then this is my fault.
But if Oracle or the network is down then this should be held by another department.
Write your code in which you build the connection in a try catch part:
try
{
BuildConnection(connectionString);
}
catch (OracleException ex)
{
//Connectivity Error
}
Errors between ORA-12150 to ORA-12236 are related to connection errors. A few examples:
ORA-12154: TNS:could not resolve the connect identifier specified
ORA-12152: TNS:unable to send break message
ORA-12157: TNS:internal network communication error
Please refer to https://docs.oracle.com/cd/E11882_01/server.112/e17766/net12150.htm
Simple answer for this Type of problem is Use Try Catch Block like
try
{
// your code
}
catch (OracleException ex)
{
}
MSDN HELP
Sure - you can catch specific exception types, or if they're all the same exception type, you can catch it, check to see if it's a specific type, and re-throw ones you don't want to handle. Not having your syntax, here's an example...
try
{
// your Oracle code
}
catch (OracleException ex)
{
if (ex.Message == "Something you don't want caught")
{
throw;
}
else
{
// handle
}
}
errors like No listener, connection lost are still caught in System.Data.SqlClient.SqlException, however, you may inspect ErrorCode and Errors to handle different situations accordingly, say, not listener or connection lost etc.
MSDN does not seem to document all possible errors, however, you may write a few unit tests or integration tests to learn what appear in ErrorCode and Errors, then write error handlers in production codes accordingly.
OracleException contains only ErrorCode not Errors. So you may be using switch(e.ErrorCode) to handle different situations.
I observed that each time a network exception occurs, then a SocketException can be found in inner exceptions.
I also observed that when a network exception occurs, the first inner exception is of type «OracleInternal.Network.NetworkException» but unfortunately, this class is internal...
Based on this observations, I would code something like this:
public void RunQuery()
{
try
{
var con = new OracleConnection("some connection string");
con.Open();
var cmd = con.CreateCommand();
// ...
cmd.ExecuteNonQuery();
}
catch (Exception ex) when (IsNetworkException(ex))
{
// Here, a network exception occurred
}
catch (Exception ex)
{
// Here, an other exception occurred
}
}
private static bool IsNetworkException(Exception ex)
{
var exTmp = ex;
while (exTmp != null)
{
if (exTmp is SocketException)
return true;
exTmp = exTmp.InnerException;
}
return false;
}

Elmah add message to error logged through call to Raise(e)

I'm a bit confused at how to add a message to an error logged programatically with ELMAH.
eg:
public ActionResult DoSomething(int id)
{
try { ... }
catch (Exception e)
{
// I want to include the 'id' param value here, and maybe some
// other stuff, but how?
ErrorSignal.FromCurrentContext().Raise(e);
}
}
It seems all Elmah can do is log the raw exception, how can I also log my own debug info?
You can throw a new Exception setting the original as the inner exception and ELMAH will log the messages for both:
catch(Exception e)
{
Exception ex = new Exception("ID = 1", e);
ErrorSignal.FromCurrentContext().Raise(ex);
}
will show
System.Exception: ID = 1 ---> System.NullReferenceException: Object reference not set to an instance of an object.
I found that I can also do something like:
Elmah.ErrorSignal.FromCurrentContext().Raise(new NotImplementedException("class FbCallback.Page_Load() Request.Url= " + Request.Url));
To log my own messages. Then in when I browse to
http://localhost:5050/elmah.axd
I see my messages as type NotImplementedException.
Not very pretty but works.

Categories

Resources