I created a QueryInterceptor on a dataservice in WCF (within SharePoint).
The "InitializeService" method is called and I'm able to debug that one,
but my QueryInterceptors don't get fired.
[QueryInterceptor("Requests")]
public Expression<Func<Request, bool>> FilterRequests()
{
Debugger.Break();
if (SPContext.Current == null) throw new DataServiceException(401, "Permission Denied");
var spUser = SPContext.Current.Web.CurrentUser;
var spLoginName = spUser.LoginName;
var spGroups = spUser.Groups.Cast<SPGroup>().Select(x => x.Name);
if (spGroups.Any(x => x == _HRApproversGroupName))
return (u) => true;
throw new DataServiceException(401, "Permission Denied");
}
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Users", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.UseVerboseErrors = true;
}
Anyone who knows what I'm doing wrong or haven't done yet?
The problem was that I referenced to the wrong QueryInterceptor (I referenced to another assembly, but with same namespaces)
Related
I'm writing an action filter for setting LastAccessDate user property. On retrieving user's record from DB, i'm getting NullReferenceException. How to get rid of this exception? Here is my Action Filter:
public class LogActivity : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var resultContext = await next();
var id = int.Parse(resultContext.RouteData.Values["id"].ToString());
var repo = resultContext.HttpContext.RequestServices.GetService<UserRepo>();
Console.WriteLine(id);
// var user = await repo.GetRespondent(id);
var user= repo.GetRespondent(id).Result; <========= Here Exception occurs
if (user != null)
{
user.LastAccessDate = DateTime.Now;
await repo.SaveAll();
}
}
}
Here is my UserRepo repository's get method:
public async Task<User> GetRespondent(int id)
{
var user= await _context.User.FirstOrDefaultAsync(u => u.Id == id);
if (user!= null)
return user
return null;
}
Replace this line
var user= repo.GetRespondent(id).Result; <========= Here Exception occurs
with
var user = await repo.GetRespondent(id);
I am making a project using asp.net core 3.1 and I can't find the right source of deleting users including roles in Asp.net core 3.1 using Web.api
This is the code I have tried but seems like not appropriate but haven't tried yet. Do you have any ideas of how to realize that?
I want to appropriately check the error using Web Api functions such as statuscode or any error messages to the frontend.
[HttpPost, ActionName("Delete")]
public async Task<ActionResult> DeleteUser(string id)
{
var user = await _userManager.FindByIdAsync(id);
var rolesForUser = await _userManager.GetRolesAsync(user);
if (rolesForUser.Count() > 0)
{
foreach (var item in rolesForUser.ToList())
{
// item should be the name of the role
var result = await _userManager.RemoveFromRoleAsync(user, item);
}
}
await _userManager.DeleteAsync(user);
return OkResult(result);
}
You don't need to loop the roles and delete , you can use RemoveFromRolesAsync :
public virtual Task<IdentityResult> RemoveFromRolesAsync(TUser user, IEnumerable<string> roles);
And each operation will return IdentityResult which could be used to check the operation status :
if (User.Identity.IsAuthenticated)
{
try
{
var user = await _userManager.FindByIdAsync(id);
var roles= await _userManager.GetRolesAsync(user);
var result = await _userManager.RemoveFromRolesAsync(user, roles);
if (result.Succeeded)
{
var resultdelete = await _userManager.DeleteAsync(user);
if (result.Succeeded)
{
return Ok();
}
else
{
List<string> errors = new List<string>();
foreach (var error in result.Errors)
{
errors.Add(error.Description);
}
return BadRequest(errors);
}
}
else
{
List<string> errors = new List<string>();
foreach (var error in result.Errors)
{
errors.Add(error.Description);
}
return BadRequest(errors);
}
}
catch (Exception exception)
{
List<string> errors = new List<string>() { exception.Message };
return StatusCode(StatusCodes.Status500InternalServerError, errors);
}
}
But use database stored procedures with transaction is always a good choice .
Given the following typical implementation of an ODataController's PUT method, how would I make the exact same method ALSO be available as a POST?
I am developing an OData end-point that will be called from an external system that I have no control over. It appears that that system implements the Update semantics (to tell my system to update an entity) wrongly by sending a POST with a uri key instead of using a PUT.
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != update.Id)
{
return BadRequest();
}
db.Entry(update).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(update);
}
My first guess was to annotate the method with [AcceptVerbs("PUT", "POST")] to make the same exact method implementation be available as a POST, but that doesn't work. It's probably that the ODataConventionModelBuilder default setup doesn't know about this...
Ideally I'd like to keep the standards based PUT and the regular POST for inserts, but add a special post that is identical to the put but differs only in the verb.
Thanks
After finding some not so evident documentation on salesforce.com on odata endpoint implementation for External Data Source/External Objects, it became evident to me that salesforce.com tries to call a POST for Update semantics on the external object but also adds the X-HTTP-METHOD set as PATCH.
So, the solution was to implement the following class:
public class MethodOverrideHandler : DelegatingHandler
{
readonly string[] _methods = { "DELETE", "HEAD", "PUT", "PATCH", "MERGE" };
const string _header1 = "X-HTTP-Method-Override";
const string _header2 = "X-HTTP-Method";//salesforce special behavior???
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Check for HTTP POST with the X-HTTP-Method-Override header.
if (request.Method == HttpMethod.Post && request.Headers.Contains(_header1))
{
// Check if the header value is in our methods list.
var method = request.Headers.GetValues(_header1).FirstOrDefault();
if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
{
// Change the request method.
request.Method = new HttpMethod(method);
}
}
else if (request.Method == HttpMethod.Post && request.Headers.Contains(_header2))
{
// Check if the header value is in our methods list.
var method = request.Headers.GetValues(_header2).FirstOrDefault();
if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
{
// Change the request method.
request.Method = new HttpMethod(method);
}
}
return base.SendAsync(request, cancellationToken);
}
}
and register it in WebApiConfig.Register(HttpConfiguration config) as such:
config.MessageHandlers.Add(new MethodOverrideHandler());
Now, the non-odata compliant POST for salesforce update operations on the External Object will get delegated to the standards compliant odata implementation (in the ODataController) of PUT method I originally posted.
I hope that this helps someone in the future...
My approach would be to throw some more logic into the method to check and see if a record already exists in the database using update.Id then checking whether or not the data is null.
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//might have to get rid of this condition for the sake of new entries
//if (key != update.Id)
//{
//return BadRequest();
//}
try
{
//not sure what the name of your table is so I'm going to call it ProductTable
var foo = db.ProductTable.Where(p => p.Id == update.Id).FirstOrDefault();
if(foo == null)
{
db.Entry(update).State = EntityState.Added;
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.Accepted);
}
else
{
db.Entry(update).State = EntityState.Modified;
await db.SaveChangesAsync();
return Updated(update);
}
}
catch (DbUpdateConcurrencyException ex)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw new DbUpdateConcurrencyException(ex.Message);
}
}
}
EDIT
Just noticed the ProductExists method... I would take that out of the catch block and throw it into the try
//for Post, pass in a 0 for key's argument
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//might have to get rid of this condition for the sake of new entries
//if (key != update.Id)
//{
//return BadRequest();
//}
try
{
if (!ProductExists(key))
{
db.Entry(update).State = EntityState.Added;
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.Accepted);
}
else
{
db.Entry(update).State = EntityState.Modified;
await db.SaveChangesAsync();
return Updated(update);
}
}
catch (DbUpdateConcurrencyException ex)
{
throw new DbUpdateConcurrencyException(ex.Message);
}
}
I'm implementing modified version of Behavior for my Windows 8 app according to this guide. It works except one place where the Reactive framework is required:
protected override void OnAttached()
{
var evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
if (evt != null)
{
Observable.FromEventPattern<RoutedEventArgs>(AssociatedObject, Event)
.Subscribe(se => FireCommand());
}
base.OnAttached();
}
The question is simple, how to achieve similar funcitonality without the Reactive frmaework? I've browsed the source of of Rx that can be obtained here, but I'ts just too complicated to me.
I've also succeeded porting to code with the only problem that it work only for fixed type of EventHandler:
protected override void OnAttached()
{
EventInfo evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
if (evt != null)
{
AssignEvent<ItemClickEventHandler>(AssociatedObject, Event, FireCommand);
}
base.OnAttached();
}
protected void AssignEvent<T1>(object instance, string eventName, T1 handler)
{
EventInfo runtimeEvent = instance.GetType().GetRuntimeEvent(eventName);
Func<T1, EventRegistrationToken> add = a => (EventRegistrationToken)runtimeEvent.AddMethod.Invoke(instance, new object[] { a });
Action<EventRegistrationToken> remove = a => runtimeEvent.RemoveMethod.Invoke(runtimeEvent, new object[] { a });
WindowsRuntimeMarshal.AddEventHandler(add, remove, handler);
}
Any idea, how to make it dynamic so I don't have to use specific event handler "ItemClickEventHandler"? Note in classic .NET it' quite simple, but in WinRT I cannot use Delegate.CreateDelegate(...)
Update:
Thanks to Brandon I was able to finish the method, it now looks like this:
protected override void OnAttached()
{
EventInfo evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
if (evt != null)
{
MethodInfo addMethod = evt.AddMethod;
MethodInfo removeMethod = evt.RemoveMethod;
ParameterInfo[] addParameters = addMethod.GetParameters();
Type delegateType = addParameters[0].ParameterType;
Action<object, object> handler = (s, e) => FireCommand(e as RoutedEventArgs);
MethodInfo handlerInvoke = typeof(Action<object, object>).GetRuntimeMethod("Invoke", new[] { typeof(object), typeof(object) });
Delegate #delegate = handlerInvoke.CreateDelegate(delegateType, handler);
Func<object, EventRegistrationToken> add = a => (EventRegistrationToken)addMethod.Invoke(AssociatedObject, new object[] { #delegate });
Action<EventRegistrationToken> remove = t => removeMethod.Invoke(AssociatedObject, new object[] { t });
WindowsRuntimeMarshal.AddEventHandler(add, remove, handler);
}
base.OnAttached();
}
Now I can remove 800kB of Rx dlls, thanks again!
I trolled through the Rx source, and here is the important bit of functionality:
MethodInfo addMethod = eventInfo.GetAddMethod();
MethodInfo removeMethod = eventInfo.GetRemoveMethod();
var addParameters = addMethod.GetParameters();
var delegateType = addParameters[0].ParameterType;
Action<object, object> handler = (object sender, object eventArgs) => FireCommand();
MethodInfo handlerInvoke = typeof(Action<object, object>).GetMethod("Invoke");
Delegate delegate = handlerInvoke.CreateDelegate(delegateType, handler);
Func<EventRegistrationToken> add = a => (EventRegistrationToken)addMethod.Invoke(instance, new object[] { delegate });
Action<EventRegistrationToken> remove = t => removeMethod.Invoke(instance, new object[] { t });
It looks like the important info is they are using MethodInfo.CreateDelegate.
I've been writing an application using MVC4 and EF5.x, and using ELMAH for logging exceptions for review. We recently released the application, and as expected the ELMAH log filled up with several dozen exceptions. Great (and not)! The problem is that one of those exceptions is
System.Data.Entity.Validation.DbEntityValidationException
Validation failed for one or more entities.
See 'EntityValidationErrors' property for more details.
Of course, there's no way to see the EntityValidationErrors property for more details and the stack trace wraps up to my SubmitChanges()
I know ELMAH has the capability of allowing us to raise our own exceptions, and in some way customize what gets logged and how. Unfortunately, I'm still very new to ELMAH and MVC and a Google search didn't turn up anything relevant. I did find a blog article on logging EntityValidationErrors, and the author specifically mentioned that he would post how to do so in ELMAH but that was posted in September of 2012 and I didn't see anything since then.
Any help would be greatly appreciated!
Probably the best thing to do in this case would be to wrap your context.SaveChanges(); call in a try...catch block and then log the individual items from the ValidationExceptions. Something like the following should get you started:
try
{
context.SaveChanges();
}
catch (DbEntityValidationException ve)
{
var error = ve.EntityValidationErrors.First().ValidationErrors.First();
var msg = String.Format("Validation Error :: {0} - {1}",
error.PropertyName, error.ErrorMessage);
var elmahException = new Exception(msg);
Elmah.ErrorSignal.FromCurrentContext().Raise(elmahException);
}
How about this extension method based on the above..
public static void SaveChangesWithBetterValidityException(this DbContext context)
{
try
{
context.SaveChanges();
}
catch (DbEntityValidationException ve)
{
var errors = new List<string>();
foreach (var e in ve.EntityValidationErrors)
{
errors.AddRange(e.ValidationErrors.Select(e2 => string.Join("Validation Error :: ", e2.PropertyName, " : ", e2.ErrorMessage)));
}
var error = string.Join("\r\n", errors);
var betterException = new Exception(error, ve);
throw betterException;
}
}
Elmah will then have a much better exception in it's log
I added the following to my Global.asax.cs in order to forward all DbEntityValidationException exceptions to Elmah across my MVC application:
private void ElmahEntityValidationException()
{
var dbEntityValidationException = Server.GetLastError() as DbEntityValidationException;
if (dbEntityValidationException != null)
{
var errors = new List<string>();
foreach (var entityError in dbEntityValidationException.EntityValidationErrors)
{
errors.AddRange(entityError.ValidationErrors.Select(e2 => string.Join("Validation Error :: ", e2.PropertyName, " : ", e2.ErrorMessage)));
}
var error = string.Join("\r\n", errors);
var betterException = new Exception(error, dbEntityValidationException);
Elmah.ErrorSignal.FromCurrentContext().Raise(betterException);
}
}
protected void Application_Error(object sender, EventArgs e)
{
ElmahEntityValidationException();
}
Some of this code was reused from #Paige Cook's and #Original10's posts.
Re-throwing as per the code below is not perfect (although I don't mind resetting the call stack here, as Elmah's logged details of the address posted to will show me what lead to the exception) and you will have to work out your own security implications, but this is fairly concise & meets my needs:
try
{
return base.SaveChanges();
}
catch (DbEntityValidationException e)
{
var de = new DetailedEntityValidationException(e);
throw de;
}
public class DetailedEntityValidationException : Exception
{
public DetailedEntityValidationException(DbEntityValidationException ve)
: base(ve.Message + ":\r\n\t-" + string.Join(new string('-',20) + "\r\n\t-", ve.EntityValidationErrors.Select(ev=>string.Join("\r\n\t-",ev.ValidationErrors.Select(e=>e.ErrorMessage)))))
{}
}
Here is my implementation for Global Web API solution for Elmah and EF Validation errors:
public class ElmahHandleWebApiErrorAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
var e = context.Exception;
// Try parse as entity error (i'm not sure of performance implications here)
var efValidationError = e as DbEntityValidationException;
if (efValidationError == null)
{
RaiseErrorSignal(e);
}
else
{
RaiseEntityFrameWorkValidationErrorSignal(efValidationError);
}
}
private static bool RaiseErrorSignal(Exception e)
{
var context = HttpContext.Current;
if (context == null)
return false;
var signal = ErrorSignal.FromContext(context);
if (signal == null)
return false;
signal.Raise(e, context);
return true;
}
private static bool RaiseEntityFrameWorkValidationErrorSignal(DbEntityValidationException e)
{
var context = HttpContext.Current;
if (context == null)
return false;
var signal = ErrorSignal.FromContext(context);
if (signal == null)
return false;
//Taken from post above
var errors = new List<string>();
foreach (var entityError in e.EntityValidationErrors)
{
errors.AddRange(entityError.ValidationErrors.Select(e2 => string.Join("Validation Error :: ", e2.PropertyName, " : ", e2.ErrorMessage)));
}
var error = string.Join("\r\n", errors);
var betterException = new Exception(error, e);
signal.Raise(betterException, context);
return true;
}
}
and then I register the attribute in the WebApiConfig.cs file under App_Start
config.Filters.Add(new ElmahHandleWebApiErrorAttribute());