Building a single entry point to a WCF service: need unified approach to return objects and collections - asp.net

Subject says it all: I'm creating a secure and generic wrapper to access a WCF service transparently.
A little background:
what I have done is that I've created similar business classes definition both on server and client. The server-side contains the actual logic while the client side contains only method definitions. Additionally, the client-side classes derive from a SecureFactory which implements a Call method. The body of every method of each derived class contains only a call to Call method. This Call method is responsible for invoking the server service passing such things as to the type of business class and which of its method to invoke to perform the requested operation.
This approach is being designed in order to simplify security checks by restricting passing of security information to only between SecureFactory and Server service. There are tuns of other benefits which you most of already aware of.
Now here's the issue: I'm stuck at as to how to return objects (especially arrays of objects) from Server to Call method?
The server may return a single business object (DataContract applied) as well as list of such objects. Since it's a generic approach, I have only Object to be used as return type. Following is the Call method
public object Call(params object[] parameters)
{
var mb = (new StackFrame(1).GetMethod());
using (Proxy.ServerClient server = new Security.BO.Proxy.ServerClient())
{
try
{
if (((MethodInfo)mb).ReturnType.IsGenericType)
{
var response = server.InvokeForList(SecurityManager.Current.SID, SecurityManager.Current.Token, mb.DeclaringType.ToString(), mb.Name, parameters);
return response.Result.ToList();
}
else
{
var response = server.Invoke(SecurityManager.Current.SID, SecurityManager.Current.Token, mb.DeclaringType.ToString(), mb.Name, parameters);
return response.Result;
}
}
catch (Exception ex)
{
System.Diagnostics.Debugger.Break();
}
}
return null;
}
server methods:
public CollectionResponse InvokeForList(string SID, string token, string type, string method, object[] parameters)
{
// Validation here
var t = assemblyBO.GetType(type, true);
object BO = Activator.CreateInstance(t);
var mi = t.GetMethod(method);
if (mi == null)
throw new MethodNotImplementedException("Method " + method + " could not be found on type " + t.ToString());
object res = mi.Invoke(BO, parameters);
// Convert list to t[]
object list = res.GetType().GetMethod("ToArray").Invoke(res, new object[0]);
// Error here! cannot convert t[] into object[]
return new CollectionResponse((object[])list);
}
The other method Invoke(...) is similar accept it returns Response object instead of CollectionResponse.
Here's the CollectionResponse class: (Response is similar:just it takes only one object)
[DataContract]
public class CollectionResponse
{
[DataMember]
private Object[] _result;
public Object[] Result
{
get
{
return _result;
}
}
public CollectionResponse(Object[] result)
{
this._result = result;
}
}
Initially I was thinking to have only one Invoke for both lists and singleton – but failed with "Connection was closed unexpectedly." still I'm not able to achieve – how can I convert T[] into object[].
Do you have any suggestion to improve it, or any other way of achieving the same?
Thanks

I can see an immediate problem here. You are using reflection which is far less perfromant than the direct call.
For me, that is enough not to follow this route.

Related

Around Advice not working when dependent on response from other REST service

I am working with Spring AOP to define a common fallback method instead of duplicating code.
I used #Around as I have to return the object from Aspect.I am trying to decide #Around advice depending on the response returned,but not able to do so.
Here is my controller:
#RequestMapping(value = "/add/employee", method = RequestMethod.GET)
public EmployeeResponse addEmployee(#RequestParam("name") String name, #RequestParam("empId") String empId) {
EmployeeResponse employeeResponse=employeeService.createEmployee(name, empId);
return employeeResponse;
}
createEmployee in the service class is used to call another endpoint to insert some data.I want to decide my advice based on the employeeResponse but not able to do so.
I tried #AfterReturning also,but I can't return the object if I use that.
Below is my aspect class:
#Around(value = "execution(* com.test.service.EmployeeService.*(..)) and args(name,empId)")
public Object getAllAdvice2(ProceedingJoinPoint pjp, String name,String empId) throws Throwable {
System.out.println("Inside Aspect");
Object[] arguments = pjp.getArgs();
if (!checkForPath()) {
return pjp.proceed();
}
System.out.println("Call Second path please!!");
return arguments;
}
private boolean checkForPath() {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getResponse();
return response.getStatus()==501?true:false;
}
}
I did use HttpServletResponse and RequestContextHolder to get the context but seems it will take the present context i.e. "/add/employee".
How can I return the actual status from the checkForPath () (since I don't need to call pjp.proceed for every status code returned) so that I can execute the line System.out.println("Call Second path please!!"); depending on my error code.
Can anyone pls suggest where it is going wrong?
Your aspect code is quite chaotic and does not make much sense:
You are trying to check for a response before calling proceed(), as R.G said. Use something like EmployeeResponse response = (EmployeeResponse) proceed() instead, inspect the response and then decide what to do next.
You already bind the method parameters to name and empId, there is no need to use pjp.getArgs().
return arguments does not make sense because you ought to return an EmployeeResponse object (either the original result or another one), not the array of method arguments.

.NET and Castle DynamicProxy - How to check if one interception is "inside" another interception

I have an AOP auditing library that intercepts methods using Castle DynamicProxy with Autofac and checks if they have this specific attribute:
[Audit(AuditOperation.Create), MethodImpl(MethodImplOptions.NoInlining)]
public virtual TEntity Add(TEntity entity, [MethodIsAuditableParam]bool methodIsAuditable = true)
{
entity = entity.DeleteNestedProperties();
using (var entityContext = ContextCreator())
{
TEntity addedEntity = entityContext.Set<TEntity>().Add(entity);
entityContext.SaveChanges();
return addedEntity;
}
}
This is a generic repository method that adds a generic entity to the database. But I also have specific methods in my Domain layer that do additional stuff and then call these generic repository methods:
[Audit(AuditOperation.Create), MethodImpl(MethodImplOptions.NoInlining)]
public virtual User AddUser(int currentUserId, User newUser, [MethodIsAuditableParam]bool methodIsAuditable = true)
{
try
{
UserDBValidations(currentUserId, newUser);
if (newUser.UserProfileId == (int)UserProfileType.Admin ||
newUser.UserProfileId == (int)UserProfileType.ProcessSpecialist)
newUser.UGBs = _ugbRepository.FindAll().ToList();
_userRepository.Add(newUser);
return newUser;
}
catch (Exception ex)
{
throw new Exception("Erro no cadastro de usuário: " + ex.Message);
}
}
My intention is that if an auditable Domain method (that can call many generic repository methods) exists, my auditing interceptor will audit only this Domain method and will ignore the generic repository audition. But if I call the generic repository methods directly, they will be audited normally.
I tried to achieve this behavior using the stack trace in my interceptor. This following method checks if the stack frames array already contains an IInterceptor.Intercept method. :
private bool CheckIfMethodCallersAreBeingIntercepted()
{
StackTrace stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames();
//the int number should match the exact number of method calls in this interception until this current method
StackFrame[] realStackFrames = stackFrames.SubArray(5, stackFrames.Count() - 5);
foreach (StackFrame realStackFrame in realStackFrames)
{
MethodBase method = realStackFrame.GetMethod();
if (method == null)
continue;
Type declaringType = method.DeclaringType;
if (declaringType == null)
continue;
string declaringTypeFullName = declaringType.FullName;
if (declaringTypeFullName == null)
continue;
if(declaringTypeFullName
.Contains("AwesomeAuditing.AwesomeAuditingInterceptor"))
return true;
}
return false;
}
But this doesn't work because I can intercept a method and don't audit it:
public void Intercept(IInvocation invocation)
{
if (!CheckIfMethodShouldBeIntercepted(invocation.Method, invocation.Arguments))
{
invocation.Proceed();
return;
}
if (!CheckIfMethodReturnTypeInheritAuditEntity(invocation.Method))
throw new AwesomeAuditingException(#"The audited method's return type most inherit the IAuditableEntity interface.");
invocation.Proceed();
if (CheckIfMethodIsAsync(invocation.Method))
invocation.ReturnValue = AsyncProceedExecution((dynamic)invocation.ReturnValue, invocation);
else
AfterProceedExecution(invocation.ReturnValue, invocation);
}
I don't want to manage a static collection with all current intercepted methods because I want this AOP library to work on many types of projects (Web API, Windows Services, Console Applications, WPF, etc.) and each type has its own way to manage static instances. For example, in a Web API context I don't want that two HTTP request share this static collection. In a Windows Service I don't want to share this static collection between two execution threads.
Do you guys know a better way to manage this multi level interception? Do you know any good practice that will work good in many project types?

Return a data object with a BadRequestResult / BadRequestErrorMessageResult

I'd like to return a data object that contains the details of the error with a BadRequestErrorMessageResult or BadRequestErrorMessageResult object like so:
public IHttpActionResult Action(Model model)
{
var validationResult = model.Validate();
if (validationResult.Successful)
{
// this one's okay; it supports sending data with a 200
return Ok(validationResult);
}
else
{
// However, how do I return a custom data object here
// like so?
// No such overload, I wish there was
// return BadRequest(validationResult);
}
}
The only three overloads of the ApiController.BadRequest() method are:
1. BadRequest();
2. BadRequest(string message);
3. BadRequest(ModelStateDictionary modelState);
Even with #3, a model state dictionary is ultimate a deep collection with one layer upon another, at the bottom of which, though, is a bunch of KeyValuePair<string, ModelError> where each ModelError also only has either a string or an Exception object.
Therefore, even with #3, we are only able to pack a string to send and not a custom object like I want to.
I am really not asking how I may go about working a hack or a kludge around the situation. My question is: is there an overload or another way baked into the .NET API to send an object to the client with a Bad Request HTTP status code?
I am using ASP.NET Web API version 5.2.4 targeting .NET Framework version 4.6.1.
You can use the Content<T>(...) method to do this. It returns a NegotiatedContentResult, which is serialized depending on the request headers (e.g. json, xml), and allows you to specify a HttpStatusCode.
You can use it like this:
return Content(HttpStatusCode.BadRequest, myObject);
If you wanted to, you could create your own BadRequest<T>(T obj) method in the controller as a wrapper, so then you could call it as you wanted:
public IHttpActionResult BadRequest<T>(T obj)
{
return Content(HttpStatusCode.BadRequest, obj);
}
public IHttpActionResult Action()
{
// do whatever validation here.
var validationResult = Validate();
// then return a bad request
return BadRequest(validationResult);
}
You can build/format the string in JSON format, pass it as string in the BadRequest() parameter and convert it to JSON again or any object on the caller's backend.
Haven't tried that but that should work.

Get Action parameters from mvc

I'm trying to get the parameters of a request on exception and log them. How can I get action parameters from a request if the parameter is an object in asp.net mvc? I can only get the parameters if I send in the parameters like this:
public virtual ActionResult TestAction(string A,string B){
}
But not like this:
public virtual ActionResult TestAction(ObjectQuery query){
}
My code:
protected override void OnException(ExceptionContext filterContext)
{
string action = filterContext.RouteData.Values["action"].ToString();
string controller = filterContext.RouteData.Values["controller"].ToString();
string parameters = filterContext.HttpContext.Request.QueryString
}
EDIT:
QueryString returns empty:
You should use reflection to achieve this:
var parameters = MethodBase.GetCurrentMethod().GetParameters();
foreach (ParameterInfo param in parameters)
{
//do your logging here
}
I maybe over simplifying it, but you can get the parameters passed to the action using the Request.Form or Request.QueryString. The nice thing about them is they are of the type NameValueCollection which makes it easy to merge them together.
Then the exception is being thrown on the respective controller so you can get the method signature via reflection, albeit without the named parameter.
Using the simple code below properly gave the parameters passed to the action and doesn't care if it is a POST or GET operation.
protected override void OnException(ExceptionContext filterContext)
{
//Get all the info we need to define where the error occured and with what data
var param = new NameValueCollection {Request.Form, Request.QueryString};
var controller = filterContext.RouteData.Values["controller"].ToString();
var action = filterContext.RouteData.Values["action"].ToString();
var signature = filterContext.Controller.GetType().GetMethod(action).ToString();
//Let's write it to the stream in this case
Response.Write(string.Format("<h3>Controller: {0}</h3>", controller));
Response.Write(string.Format("<h3>Action: {0}</h3>", action));
Response.Write(string.Format("<h4>Signature: {0}</h4>", signature));
foreach (var key in param.AllKeys)
{
Response.Write(string.Format("<strong>Key:</strong> {0} = {1}<br />", key, param[key]));
}
Response.End();
}
There are some downsides I would imagine though. Collections will probably be represented in a very unfriendly way. Data which wasn't supposed to bind with the specific model will be shown as well.

ObjectDisposedException While using Include - why?

My page calls a Services layer method that uses a Generic Repository "Find" method. In the services layer method, I do the following:
using (IUnitOfWork unitOfWork = new DBContext())
{
GenericRepository<Operator> operatorRepos = new GenericRepository<Operator>(unitOfWork);
{
try
{
var oper = operatorRepos.Find(o => o.OperatorID == operatorID).Include(o => o.cmn_Address).Single();
return oper;
}
catch (InvalidOperationException exc)
{
//handle exception
}
}
}
The Find method for my repository:
public IQueryable<T> Find(Func<T, bool> predicate)
{
return _objectSet.Where<T>(predicate).AsQueryable();
}
On the page, I try to access the cmn_address Navigation property of the Operator and I get the following error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I realize that this is caused by the using statement to dispose of the context, but I thought the Include method will eager load the cmn_Address object. I don't understand why this doesn't work as I expected.
You are using Func<> instead of Expression<Func<>> in your where condition. That makes it Linq-to-objects. This change is permanent. Calling AsQueryable doesn't make it Linq-to-entities again.

Resources