I have various methods that does the same things.
Attached below the code :
private async Task<CheckResponse> ManageCheckResponseError(string code)
{
await LogErrorResponseAsync(new { StatusCode = code });
return CheckResponse.GetError(code.ToString());
}
private async Task<BalanceResponse> ManageBalanceResponseError(string code)
{
await LogErrorResponseAsync(new { StatusCode = code });
return BalanceResponse.GetError(code.ToString());
}
private async Task<DebitResponse> ManageDebitResponseError(string code)
{
await LogErrorResponseAsync(new { StatusCode = code });
return DebitResponse.GetError(code.ToString());
}
private async Task<CreditResponse> ManageCreditResponseError(string code)
{
await LogErrorResponseAsync(new { StatusCode = code });
return CreditResponse.GetError(code.ToString());
}
private async Task<CancelResponse> ManageCancelResponseError(string code)
{
await LogErrorResponseAsync(new { StatusCode = code });
return CancelResponse.GetError(code.ToString());
}
An example of these classes is as follows. All are made in the same way apart from the properties that obviously are different :
public class SampleResponse : ICommonResponseOperations<SampleResponse>
{
// Props
// Error Management
public ErrorModel ErrorModel { get; set; }
public static LoginResponse GetError(string code)
{
return new LoginResponse
{
Entry = "",
EntryEmbedded = "",
ErrorModel = ErrorModel.GetError(code)
};
}
}
Is there a way through generics to standardize everything by making the code more elegant? Thank you
In the next version of C# (11) you will be able to define static members of interfaces.
You can try that out in the latest version of Visual Studio 2022 by adding the following to your project file (assuming .NET 6.0):
<EnablePreviewFeatures>True</EnablePreviewFeatures>
<LangVersion>preview</LangVersion>
After doing that you can modify your ICommonResponseOperations interface with a static member like so:
public interface ICommonResponseOperations<out TLoginResponse>
{
static abstract TLoginResponse GetError(string code);
// ... Other members
}
(You might need to remove the out depending on how the TLoginResponse type is used in the interface.)
Then you could define a common generic method like so:
private async Task<TLoginResponse> ManageResponseError<TLoginResponse>(string code) where TLoginResponse : ICommonResponseOperations<TLoginResponse>
{
await LogErrorResponseAsync(new { StatusCode = code });
return TLoginResponse.GetError(code);
}
Then instead of:
private async Task<BalanceResponse> ManageBalanceResponseError(string code)
{
await LogErrorResponseAsync(new { StatusCode = code });
return BalanceResponse.GetError(code.ToString());
}
You could just call ManageResponseError<BalanceResponse>(code) without having to specify a separate method to call.
Of course, C#11 isn't out yet and this feature is not guaranteed to make it, but it's looking pretty likely.
You can also simplify things a little with C#10.
You can write a generic method which accepts a Func<string, TLoginResponse> that it can call to return the necessary object:
public async Task<TLoginResponse> ManageResponseError<TLoginResponse>(
string code,
Func<string /*code*/, TLoginResponse> getError)
where TLoginResponse : ICommonResponseOperations<TLoginResponse>
{
await LogErrorResponseAsync(new { StatusCode = code });
return getError(code);
}
Then you can call the method without having to explicitly specify the generic type:
await ManageResponseError("some code", SampleResponse.GetError);
The generic type is inferred from the type of the lambda passed in at the call site.
Even the lambda itself (code => SampleResponse.GetError(code)) is inferred, so you only need to specify SampleResponse.GetError.
Related
I am overriding a method in a base class library. However, inside my overridden implementation I am using the new HttpClient which is all based on async methods. I therefore have to mark my method as async, which means that I need to change the return parameter of the method from string to Task. The compiler however gives an error: "The return type must be 'string' to match overridden member ...."
public class BaseClass
{
public virtual string GetName()
{
...
}
}
public class MyClass : BaseClass
{
public override async Task<string> GetName()
{
HttpClient httpClient = new HttpClient();
var response = await httpClient.GetAsync("");
if (response.IsSuccessStatusCode)
{
var responseContent = response.Content;
return await responseContent.ReadAsStringAsync();
}
return null;
}
}
Of course the obvious solution would be to change the return type of GetName() in BaseClass to Task<string>, but I have no control over BaseClass as it is an external library;
My current solution is to use the HttpClient classes in a synchronous fashion, i.e. change MyClass as follows:
public class MyClass : BaseClass
{
public override string GetName()
{
HttpClient httpClient = new HttpClient();
var response = httpClient.GetAsync("");
if (response.Result.IsSuccessStatusCode)
{
var responseContent = response.Result.Content;
return responseContent.ReadAsStringAsync()
.Result;
}
return null;
}
}
Is there any other way to do this?
Unfortunately there isn't a good solution here. There is no way to override a non-async method with an async one. I think your best bet is to have an async non-override method and call into that from the non-async one:
public class MyClass : BaseClass
{
public override string GetName()
{
return GetNameAsync().Value;
}
public async Task<string> GetNameAsync()
{
...
}
}
Note that this can cause problems though. If the original code didn't expect for any async code to be executing introducing this pattern could break expectations. I would avoid it if possible.
Luckily the ReadAsStringAsync().Result is not causing a deadlock since it is likely to have ConfigureAwait(false) within.
To prevent a deadlock, you could use one of the following methods:
public static T GetResult<T>(Func<Task<T>> func)
{
var httpContext = HttpContext.Context;
var proxyTask = Task.Run(() =>
{
HttpContext.Context = httpContext;
return func();
});
return proxyTask.Result;
}
// or
public static T GetResult<T>(Func<Task<T>> func)
{
var syncContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
var task = func();
SynchronizationContext.SetSynchronizationContext(syncContext);
return task.Result;
}
This way you would call
public override string GetName()
{
...
return GetResult(() => responseContent.ReadAsStringAsync());
...
}
The former has a performance overhead by spawning a new thread, while the latter suffers from breaking SynchronizationContext flow, which makes any context bound to it unavailable in the task being called, e.g. HttpContext.Current.
I've also had this problem, and the solution was using an interface, in which 'async' isn't part of the method's signature.
public abstract class Base : IInvokable {
/* Other properties ... */
public virtual async Task Invoke() {
/*...*/
}
}
public interface IInvokable {
Task Invoke();
}
public class Derived
{
public override async Task Invoke() {
// Your code here
}
}
I am doing an database update operation and updating some of the fields based on type being passed to the internal method with switch case statement, at the moment it has 4 case statements and it will grow bigger..
I am looking a way to convert this switch case to dictionary with key value pair or any kind of mechanism to implement inside method.
This is main method
public async Task<MutationResponse> SetRequestStage(string requestStage, Guid requestId, MasterSectionEnum masterSectionEnum)
{
var request = _dbContext.Requests.SingleOrDefault(r => r.Id == requestId);
var rs = _dbContext.RequestStages.SingleOrDefault(rs => rs.Name == requestStage);
if (rs != null)
{
request.RequestStage = rs;
if (rs.Name == "Approved")
{
switch (masterSectionEnum)
{
case MasterSectionEnum.LOCALCODE:
await UpdateRevision<LocalCode>(request.DataId).ConfigureAwait(false);
break;
case MasterSectionEnum.NATIONALCODE:
await UpdateRevision<NationalCode>(request.DataId).ConfigureAwait(false);
break;
case MasterSectionEnum.GUIDELINES:
await UpdateRevision<Guideline>(request.DataId).ConfigureAwait(false);
break;
case MasterSectionEnum.LIBRARYA621:
await UpdateRevision<LibraryA621>(request.DataId).ConfigureAwait(false);
break;
case .....
case .....
default:
throw new ArgumentException($"SetRequestStage Error: invalid MasterSection {masterSectionEnum.ToString()}");
}
}
}
_dbContext.SaveChanges();
return new MutationResponse();
}
and this will be the enum
public enum MasterSectionEnum
{
LOCALCODE,
NATIONALCODE,
GUIDELINES,
SPACETYPE,
LIBRARYA621
// this will grow bigger
}
and this will be the internal method that i am calling from above method
private async Task UpdateRevision<T>(Guid id) where T : class, IAEIMaster, IRevisionData
{
var dbSet = this._dbContext.Set<T>();
var code = dbSet.SingleOrDefault(c => c.Id == id);
......
......
code.Revision = revision;
code.IsApproved = true;
}
could any one suggest on how to convert this switch case to alternative kind with key value pair or with types that would be very grateful to me.
many thanks in advance
Update : i am looking kind of below method, I am using dot net core with EF core
var types = new Dictionary<string, string>();
foreach(var item in types)
{
if(item.Key == "enum value")
{
await UpdateRevision<item.value>(request.DataId).ConfigureAwait(false);
}
}
Instead of passing in the parameter MasterSectionEnum, change your method to accept a type parameter. Then just use that generic type in a single call of UpdateRevision.
public async Task<MutationResponse> SetRequestStage<SectionType>(
string requestStage,
Guid requestId
) {
...
await UpdateRevision<SectionType>(request.DataId).ConfigureAwait(false);
....
}
If all valid types of SectionType share an interface or are derived from the same class, then you can take it further and add a constraint to the SectionType and avoid having to handle bad types at runtime.
Edit:
So SetRequestStage can't be generic huh? Well, the inclination to make it generic stems from the fact that it depends on UpdateRevision, which is generic. This in turn depends on DbContext.Set(). And you're using a generic version of it. But the good news is that there seems to be a non-generic version of it that accepts a type variable as a parameter. So:
async Task UpdateRevision<T>(
Guid id,
Type t
) where T : class, IAEIMaster, IRevisionData {
var dbSet = this._dbContext.Set(t);
...
}
And then:
public async Task<MutationResponse> SetRequestStage(
string requestStage,
Guid requestId,
Type SectionType
) {
...
await UpdateRevision(request.DataId, SectionType).ConfigureAwait(false);
....
}
I don't know what your UI looks like. But, generically:
var dic = new Dictionary<MasterSectionEnum, Type> {
{ MasterSectionEnum.LOCALCODE, typeof(LocalCode) },
{ MasterSectionEnum.NATIONALCODE, typeof(NationalCode) },
...
};
public async someUiRelatedMethod(
string reqStage,
Guid reqId,
MasterSectionEnum sectionType
) {
await SetRequestStage(reqStage, reqId, dic[sectionType]);
}
Sorry if the syntax on the latter isn't quite right. But you get the idea.
You can try this:
public enum MasterSectionEnum
{
LOCALCODE,
NATIONALCODE
}
public sealed class LocalCode { }
public sealed class NationalCode { }
public sealed class Program
{
private static readonly Dictionary<MasterSectionEnum, Func<Guid, Task>> Dictionary
= new Dictionary<MasterSectionEnum, Func<Guid, Task>>();
static Program()
{
Dictionary[MasterSectionEnum.LOCALCODE] = UpdateRevision<LocalCode>;
Dictionary[MasterSectionEnum.NATIONALCODE] = UpdateRevision<NationalCode>;
}
public static async Task SetRequestStage(MasterSectionEnum masterSectionEnum)
{
await Dictionary[masterSectionEnum].Invoke(Guid.NewGuid());
}
private static Task UpdateRevision<T>(Guid id) where T : class
{
Console.WriteLine(typeof(T));
return Task.CompletedTask;
}
public static async Task Main()
{
await SetRequestStage(MasterSectionEnum.LOCALCODE);
await SetRequestStage(MasterSectionEnum.NATIONALCODE);
Console.ReadKey();
}
}
Result:
LocalCode
NationalCode
I'm working on a class responsible for communicating with O365 using the Microsoft Graph Client Library. In each method, the call to NextPageRequest.GetAsync() is on a different type which also returns a different type, but otherwise the pagination logic is identical:
public async Task<List<Microsoft.Graph.User>> FindAllUsers()
{
var usersFound = new List<Microsoft.Graph.User>();
var usersPage = await GraphClient.Users.Request().GetAsync();
usersFound.AddRange(usersPage);
while (usersPage.NextPageRequest != null)
{
usersPage = await usersPage.NextPageRequest.GetAsync();
usersFound.AddRange(usersPage);
}
return usersFound;
}
public async Task<List<Microsoft.Graph.Group>> FindAllGroups()
{
var groupsFound = new List<Microsoft.Graph.Group>();
var groupsPage = await GraphClient.Groups.Request().GetAsync();
groupsFound.AddRange(groupsPage);
while (groupsPage.NextPageRequest != null)
{
groupsPage = await groupsPage.NextPageRequest.GetAsync();
groupsFound.AddRange(groupsPage);
}
return groupsFound;
}
public async Task<List<Microsoft.Graph.User>> FindGroupMembers(string groupId)
{
var usersFound = new List<Microsoft.Graph.User>();
var membersPage = await GraphClient.Groups[groupId].Members.Request().GetAsync();
usersFound.AddRange(membersPage.Where(d => d.ODataType.Equals("#microsoft.graph.user")).Cast<Microsoft.Graph.User>());
while (membersPage.NextPageRequest != null)
{
membersPage = await membersPage.NextPageRequest.GetAsync();
usersFound.AddRange((List<Microsoft.Graph.User>)membersPage);
}
return usersFound;
}
I would like to write generic method to reduce duplication, but in each of the above methods, the return type of GetAsync is a different interface that defines its own NextPageRequest property on itself. This makes it impossible to tell the generic method what specific type it will need to call NextPageRequest on so that the method can compile.
Is there a way to improve upon this, or do I just need to accept the duplicated logic for each query type I want to implement?
Thanks to Microsoft Graph API architects, it looks like we can only get rid of such sort of redundancy either by using reflection or dynamics. Since dynamics, in theory, should provide better performance, here's a version of sample code based on them:
private void ProcessAllResultPages<TResult, TItem>(IBaseRequest request,
Action<TResult> processorDelegate)
where TResult : ICollectionPage<TItem>
{
do
{
Task<TResult> task = ((dynamic)request).GetAsync();
processorDelegate(task.Result); // This will implicitly call Wait() on the task.
request = ((dynamic)task.Result).NextPageRequest;
} while (request != null);
}
Sample usage:
IGraphServiceGroupsCollectionRequest request = graphServiceClient.Groups.Request().
Filter(...).
Select(...).
Top(pageSize);
ProcessAllResultPages<IGraphServiceGroupsCollectionPage, Group>(request,
result =>
{
// Process page results here.
});
I used this to reduce duplication of code:
public async Task<List<T>> GetAllAsync<T>(IBaseRequest baseRequest)
where T : DirectoryObject
{
List<T> pagedItems = new();
try
{
var pageOfItems = await ((dynamic)baseRequest).GetAsync();
pagedItems.AddRange(pageOfItems);
while (pageOfItems.NextPageRequest != null)
{
pageOfItems = await pageOfItems.NextPageRequest.GetAsync();
pagedItems.AddRange(pageOfItems);
}
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
return pagedItems;
}
And then use it with:
var result = await GetAllAsync<Microsoft.Graph.Group>(_graphServiceClient.Groups.Request());
var result = await GetAllAsync<Microsoft.Graph.User>(_graphServiceClient.Users.Request());
I have wrote Generic Methods for Get,Post and Put. An example of Get Generic Method is :
public async Task<object> GetAsync<T>(string uri, NamingStrategy namingStrategy)
{
using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri))
{
return await ProcessAsync<T>(requestMessage, namingStrategy);
}
}
and ProcessAync is :
public async Task<object> ProcessAsync<T>(HttpRequestMessage request, NamingStrategy namingStrategy)
{
if (!string.IsNullOrEmpty(AuthToken))
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken);
}
HttpResponseMessage response = await _client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
_logger.LogInformation("Request Succeeded");
var dezerializerSettings = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = namingStrategy
}
};
T responseModel = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync(), dezerializerSettings);
return responseModel;
}
else
{
return await GetFailureResponseModel(response);
}
}
than i am calling this get method like that in my SingletonClass
public async Task<object> GetShops(string category)
{
_logger.LogInformation("ClubMatas outgoing request: {RequestName}", nameof(GetShops));
return await _client.GetAsync<ShopsResponseModel>($"v2/shops?category={WebUtility.UrlEncode(category)}");
}
And this method is called in my Controller like this
public async Task<ActionResult<object>> GetShops([FromQuery(Name = "category")]string category)
{
var response = await _httpClient.GetShops(category);
return ParseResponse<ShopsResponseModel>(response);
}
and ParseResponse is
protected ActionResult<object> ParseResponse<T>(object response)
{
if (response.GetType() == typeof(T))
{
return Ok(response);
}
else
{
return Error(response);
}
}
As the call chain shows, I am expecting other SuccessModel or FailureModel in my Api response and due to that I have to use object as return type. But I have feeling that I shouldn't be using object type for return. FYI above chain works fine. I am just looking for more refactoring or enhancement of my current flow. looking for more elegant solution to this problem. Please do suggest any other solution for my problem.
Update
I tried #ChrisPratt suggestion of using Interface, but that solution is not working or maybe i am doing it wrong. So i created this empty Interface
public interface IResult
{
}
And I extended Both my ShopResponseModel and FailureResponseModel from IResult Interface, and updated methods like this.
public async Task<IResult> GetShops(string category)
{
_logger.LogInformation("ClubMatas outgoing request: {RequestName}", nameof(GetShops));
return await _client.GetAsync<IResult>($"v2/shops?category={WebUtility.UrlEncode(category)}");
}
and
public async Task<T> GetAsync<T>(string uri, NamingStrategy namingStrategy)
{
using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri))
{
return await ProcessAsync<T>(requestMessage, namingStrategy);
}
}
and I updated ProcessAsync return type from object to T. But getting errors.
But I have feeling that I shouldn't be using object type for return.
Yes. Don't use object for return values. It's virtually useless as a return type. What you should be doing is returning an interface. For example, you can do something like:
public interface IResponseStatusModel
{
bool Succeeded { get; }
int StatusCode { get; }
// etc.
}
Then:
public class SuccessModel : IResponseStatusModel
public class FailureModel : IResponseStatusModel
Then, you can return IResponseStatusModel, and based on the interface, you'll be able to interact with any property or method defined on the interface, regardless of which model you actually return.
However, you really shouldn't have separate classes for success/failure. Creating an interface that can generically allow you to interact with either one is going to lead to blurring the lines between the two, anyways. Instead, you should simply return a single model type, that has properties like the above and maybe a list property for errors and such. For example:
public class ProcessResult
{
public ProcessResult(int statusCode) : this(statusCode, null) {}
public ProcessResult(int statusCode, IEnumerable<string> errors)
{
Succeeded = statusCode < 300;
StatusCode = statusCode;
Errors = errors;
}
public bool Succeeded { get; private set; }
public int StatusCode { get; private set; }
public IEnumerable<string> Errors { get; private set; }
}
That's a very basic example. You might want to build it out more and provide a more robust solution for determining whether the task succeeded or not. The general idea is that you provide as much relevant information as possible concerning the result of the operation. Then, in your code, you can simply branch on Succeeded and then handle the situation accordingly:
if (result.Succeeded)
{
// do something on success
}
else
{
// do something on failure
}
I have a system which uses AOP with ContextBoundObject.
This is used to intercept a method call and perform certain operations before and after the function. It all works fine until I make the 'function to be intercepted' async.
I understand that the C# compiler rewrites async methods into a state machine, which returns control to the sink as soon as 'await' is reached
So it continues into the interception and executes the code which is meant to be executed only after the Method.
I can see there is an "AsyncProcessMessage" in IMessageSink, but I can't find a way to invoke it, and I am not sure if it will work in the async/await scenario.
Is there a way to make Async/Await work with the ContextBoundObject? Is using another Aspect Oriented Programming approach the only option here?
The code sample below has the method to be intercepted decorated with the 'Audit' attribute and placed in the AuditFacade which is a ContextBoundObject. The SyncProcessMessage method in the AuditSink has the logic to be executed before and after the method.
[AuditBoundary]
public class AuditFacade : ContextBoundObject
{
[Audit]
public ResponseObject DoSomthing()
{
//Do something
return new ResponseObject();
}
/// <summary>
/// Async Method to be intercepted
/// </summary>
/// <returns></returns>
[Audit]
public async Task<ResponseObject> DoSomthingAysnc()
{
//Do something Async
await Task.Delay(10000);
return new ResponseObject();
}
}
[AttributeUsage(AttributeTargets.Method)]
public class AuditAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Class)]
public class AuditBoundaryAttribute : ContextAttribute
{
public AuditBoundaryAttribute()
: base("AuditBoundary" + Guid.NewGuid().ToString())
{
}
public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
ctorMsg.ContextProperties.Add(new AuditProperty());
}
}
public class AuditProperty : IContextProperty, IContributeObjectSink
{
public string Name
{
get { return "AuditProperty"; }
}
public bool IsNewContextOK(Context newCtx)
{
var p = newCtx.GetProperty("AuditProperty") as AuditProperty;
if (p == null)
return false;
return true;
}
public void Freeze(Context newContext)
{
}
public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
{
return new AuditSink(nextSink);
}
}
public class AuditSink : IMessageSink
{
private IMessageSink nextSink;
public AuditSink(IMessageSink nextSink)
{
this.nextSink = nextSink;
}
public IMessage SyncProcessMessage(IMessage msg)
{
var message = msg as IMethodCallMessage;
IMethodReturnMessage returnMessage = null;
ResponseObject response;
//Some Pre Processing happens here
var newMessage = new MethodCallMessageWrapper(message);
//Invoke the Method to be Audited
returnMessage = nextSink.SyncProcessMessage(newMessage) as IMethodReturnMessage;
response = returnMessage.ReturnValue as ResponseObject;
//Some Post Processing happens here with the "response"
return returnMessage;
}
public IMessageSink NextSink
{
get { return this.nextSink; }
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
return nextSink.AsyncProcessMessage(msg, replySink);
}
}
I don't know anything about ContextBoundObject, but I think that AsyncProcessMessage() has nothing to do with async-await and that the following should work using the normal SyncProcessMessage():
Do your preprocessing step.
Invoke the async method.
Add your postprocessing step as a continuation to the returned Task, using ContinueWith() or await.
Return the continuation Task to the caller.
If you're okay with your postprocessing executing on the thread pool, then ContinueWith() is probably simpler. If you need the postprocessing to execute on the original context, use await.
The await version could look like this:
var responseTask = (Task<ResponseObject>)returnMessage.ReturnValue;
Func<Task<ResponseObject>> postProcessTaskFunc = async () =>
{
var response = await responseTask;
// Some Post Processing happens here with the "response"
return response;
}
return new ReturnMessage(postProcessTaskFunc(), …);