Reducing code duplication with Microsoft Graph Client Library - c#

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());

Related

How to unify similar methods in c #

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.

How to properly make app async with "async" and "await"?

class Website
{
public Website(string link)
{
_linkToWeb = new RestClient(link);
}
public async Task<string> DownloadAsync(string path)
{
var request = new RestRequest(path, Method.GET);
var response = _linkToWeb.ExecuteAsync(request);
return response.Result.Content;
}
public RestClient _linkToWeb { get; set; }
}
class Program
{
public static Website API = new Website("https://api.collegefootballdata.com");
public static async Task<string> _downloadTeamsFromAPI()
{
return API.Download("/teams/fbs");
}
public static async Task<string> _downloadAdvancedInfoFromAPI()
{
return API.Download("/stats/season/advanced?year=2010");
}
public static async Task<Teams> _addTeamToDB(Teams item)
{
var tmp = new Teams
{
School = item.School,
Abbreviation = item.Abbreviation,
Conference = item.Conference,
Divison = item.Divison,
Color = item.Color,
Alt_Color = item.Alt_Color,
Team = await _getAdvancedInfoFromAPI(item.Conference)
};
return tmp;
}
public static async Task<string> _getAdvancedInfoFromAPI(string _conferenceName)
{
List<Advanced> advancedDataList = new List<Advanced>();
var advancedData = await _downloadAdvancedInfoFromAPI();
var advancedDataDeserialized = JsonSerializer.Deserialize<Advanced[]>(advancedData, new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
});
foreach (var item in advancedDataDeserialized)
{
advancedDataList.Add(new Advanced
{
Team = item.Team,
//Conference = item.Conference,
Year = item.Year,
excludeGarbageTime = item.excludeGarbageTime,
startWeek = item.startWeek,
endWeek = item.endWeek
});
}
return await _lookForMatch(_conferenceName, advancedDataList);
}
public static async Task<string> _lookForMatch(string _Confa, List<Advanced> lista)
{
return lista
.Where(x => x.Conference == _Confa)
.Select(x => x.Team)
.FirstOrDefault();
}
public static async Task Main()
{
Console.WriteLine("Odpaliłem program!\n");
using var db = new Context();
db.Database.EnsureCreated();
Console.WriteLine("Stworzylem baze!\n");
var teams = await _downloadTeamsFromAPI();
var deserializer = JsonSerializer.Deserialize<Teams[]>(teams, new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
});
Console.WriteLine("Zdeserializowalem dane!\n");
foreach (var item in deserializer)
{
db.Teams.Add(await _addTeamToDB(item));
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss"));
Console.WriteLine("Dodalem element do bazy...\n");
};
db.SaveChanges();
Console.WriteLine("Zapisalem dane do bazy!");
}
}
I know it's a noob question but I don't know how to make it work :/
I want to make it a bit asynchronous, because the words async and await doesn't exactly make it more asynchronous, but I don't know how to make it work anyhow asynchronous.
The app first downloads the information from API, deserializes it and stores it into var type variable. Then it downloads the advanced info from API and joins it by "Conference" item. (that is on purpose, even though it's not optimal).
There are a lot of asyncs and awaits but I don't think it anyhow runs asynchronously. What should I change to make this app actually async?
I appreciate your motive to write asynchronous code to make your application more scalable.
However after going through the sample code posted, I am afraid you need to do more learning on the concepts of asynchronous programming rather than just jumping into the console and trying to write some code which looks like asynchronous code.
Start slowly and try to understand the purpose of Task library, when to use it. What await does behind the scenes. When to wrap a return type with Task and when to mark a method as async. These are some of the main keywords which you come across in asynchronous code and a good understanding of these is a must to write/understand asynchronous code.
There are plenty of resources available online to get a hang of these concepts. For starters, you can begin looking into Microsoft Documentation
Having said that, inline is a rewrite of the sample code with proper use of async/await.
Please use this for references purpose only. Do not try to put into some production code until unless you have a good understanding of the concept.
Necessary comments are provided to explain some critical changes made.
class Website
{
public Website(string link)
{
_linkToWeb = new RestClient(link);
}
public async Task<string> DownloadAsync(string path)
{
var request = new RestRequest(path, Method.GET);
var response = await _linkToWeb.ExecuteAsync(request); //await an asynchronous call.
return response.Content; //No need to call response.Result. response content can be fetched after successful completion of asynchronous call.
}
public RestClient _linkToWeb { get; set; }
}
class Program
{
public static Website API = new Website("https://api.collegefootballdata.com");
public static async Task<string> _downloadTeamsFromAPI()
{
return await API.DownloadAsync("/teams/fbs");
}
public static async Task<string> _downloadAdvancedInfoFromAPI()
{
return await API.DownloadAsync("/stats/season/advanced?year=2010");
}
public static async Task<Teams> _addTeamToDB(Teams item)
{
var tmp = new Teams
{
School = item.School,
Abbreviation = item.Abbreviation,
Conference = item.Conference,
Divison = item.Divison,
Color = item.Color,
Alt_Color = item.Alt_Color,
Team = await _getAdvancedInfoFromAPI(item.Conference)
};
return tmp;
}
//Return type has to be Task<Teams> rather than Task<string> because the return object is Teams.
public static async Task<Teams> _getAdvancedInfoFromAPI(string _conferenceName)
{
List<Advanced> advancedDataList = new List<Advanced>();
var advancedData = await _downloadAdvancedInfoFromAPI();
var advancedDataDeserialized = JsonSerializer.Deserialize<Advanced[]>(advancedData, new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
});
foreach (var item in advancedDataDeserialized)
{
advancedDataList.Add(new Advanced
{
Team = item.Team,
//Conference = item.Conference,
Year = item.Year,
excludeGarbageTime = item.excludeGarbageTime,
startWeek = item.startWeek,
endWeek = item.endWeek
});
}
return _lookForMatch(_conferenceName, advancedDataList);
}
//Return type is Teams and not string.
//Moreover Task<string> not required because we are not awaiting method call in this method.
public static Teams _lookForMatch(string _Confa, List<Advanced> lista)
{
return lista.Where(x => x.Conference == _Confa)
.Select(x => x.Team)
.FirstOrDefault();
}
public static async Task Main()
{
Console.WriteLine("Odpaliłem program!\n");
using var db = new Context();
db.Database.EnsureCreated();
Console.WriteLine("Stworzylem baze!\n");
var teams = await _downloadTeamsFromAPI();
var deserializer = JsonSerializer.Deserialize<Teams[]>(teams, new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
});
Console.WriteLine("Zdeserializowalem dane!\n");
foreach (var item in deserializer)
{
db.Teams.Add(await _addTeamToDB(item));
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss"));
Console.WriteLine("Dodalem element do bazy...\n");
};
db.SaveChanges();
Console.WriteLine("Zapisalem dane do bazy!");
}
}

Is it possible to use method attributes to change how this method is run?

I have this method:
public object LongRunningTask()
{
return SomethingThatTakesTooLong();
}
I wrote the following code so I can transform a normal method in an async one and still get the Exception:
public async Task<object> LongRunningTaskAsync()
{
Exception ex = null;
object ret = await Task.Run(() =>
{
object r = null;
try
{
//The actual body of the method
r = SomethingThatTakesTooLong();
}
catch (Exception e)
{
ex = e;
}
return r;
});
if (ex == null)
return ret;
else
throw ex;
}
When I need to do this in several methods, I have to copy all this code and change only the middle.
Is there a way to do something like this?
[SomeAttributeThatDoesThatMagically]
public async Task<object> LongRunningTaskAsync()
{
return SomethingThatTakesTooLong();
}
Attributes are generally metadata though it is possible to define attributes that can be executed (such as security behaviours in WCF) however, something has to be looking for it first. Your attributes won't just magically run.
I suspect you might have to use a dynamic proxy.
Take a look at how WCF does things for ideas.

How can you await a Task when you can't await

I'm developing a Windows 8 Runtime Component so the public interface can't contain Task<T> as it's not a windows runtime type.
This means I can't mark the method as async and can't await the private async methods in my library. This is leading to some confusion about how to handle my application logic.
This is how I'd do what I want synchronously.
Result r = TryGetAuthResultFromFile();
if(r != null)
{
return r;
}
r = GetAuthResultFromWebAuthenticationBroker();
return r;
The problem is that TryGetResultFrom file are async Task<Result> methods and the method that's returning r is returning IAsyncOperation<Result>
I've tried this (this isn't complete code but the theory can be seen, handle the results in continuations and return them, I'd have to do some frigging of results to IAsyncOperation types).
TryGetAuthResultFromFile().ContinueWith(x=>
{
if(x.Result != null)
{
return x.result;
}
GetAuthResultFromWebAuthenticationBroker().ContinueWith(y=>
{
return y.Result;
});
});
The problem with this is that the WebAuthenticationBroker doesn't seem work if it's not being called from the UI thread. It throws a helpful NotImplementedException without a useful error message.
How can I call TryGetAuthResultFromFile then wait for the result, then call GetAuthResultFromWebAuthenticationBroker?
Your interface can't use Task/Task<T>, but it can use IAsyncAction/IAsyncOperation<T>.
Your implementation can use Task/Task<T> if you have a wrapper that calls AsAsyncAction/AsAsyncOperation/AsyncInfo.Run as appropriate.
public interface IMyInterface
{
IAsyncOperation<MyResult> MyMethod();
}
public sealed class MyClass: IMyInterface
{
private async Task<MyResult> MyMethodAsync()
{
var r = await TryGetAuthResultFromFileAsync();
if (r != null)
return r;
return await GetAuthResultFromAuthenticationBrokerAsync();
}
public IAsyncOperation<MyResult> MyMethod()
{
return MyMethodAsync().AsAsyncOperation();
}
}

Validating model properties WCF Web APi

I have a set of services hosted with WCF Web Api, what I need to do is validate the properties inside the models of the app.
In MVC 3 for example I decorate properties in the model like this:
[StringLength(30)]
public string UserName { get; set; }
and then in the controller I proceed like this to verify os the model has met the validation parameters:
[HttpPost]
ActionResult Create(Model myModel)
{
if(ModelState.IsValid(){
Post the model
}
else
{
Don't post the model
}
}
Is there a way to do something similar in WCF Web Api?
Ok I finally managed to get validations for my models working. I wrote a validation handler and a couple of extensions methods. First thing the validation handler:
public class ValidationHandler<T> : HttpOperationHandler
{
private readonly HttpOperationDescription _httpOperationDescription;
public ValidationHandler(HttpOperationDescription httpOperationDescription)
{
_httpOperationDescription = httpOperationDescription;
}
protected override IEnumerable<HttpParameter> OnGetInputParameters()
{
return _httpOperationDescription.InputParameters
.Where(prm => prm.ParameterType == typeof(T));
}
protected override IEnumerable<HttpParameter> OnGetOutputParameters()
{
return _httpOperationDescription.InputParameters
.Where(prm => prm.ParameterType == typeof(T));
}
protected override object[] OnHandle(object[] input)
{
var model = input[0];
var validationResults = new List<ValidationResult>();
var context = new ValidationContext(model, null, null);
Validator.TryValidateObject(model, context, validationResults,true);
if (validationResults.Count == 0)
{
return input;
}
else
{
var response = new HttpResponseMessage()
{
Content = new StringContent("Model Error"),
StatusCode = HttpStatusCode.BadRequest
};
throw new HttpResponseException(response);
}
}
}
Notice how the Handler receives a T object, this is mainly because I would like to validate all the model types within the API. So the OnGetInputParameters specifies that the handler needs to receive a T type object, and the OnGetOutputParameters specifies that the handler needs to return an object with the same T type in case validations policies are met, if not, see how the on handle method throws an exception letting the client know that there's been a validation problem.
Now I need to register the handler, for this I wrote a couple of extensions method, following an example of a Pedro Felix's blog http://pfelix.wordpress.com/2011/09/24/wcf-web-apicustom-parameter-conversion/ (this blog helped me a lot, there are some nice explanations about the whole handler operations thing). So these are the extensions methods:
public static WebApiConfiguration ModelValidationFor<T>(this WebApiConfiguration conf)
{
conf.AddRequestHandlers((coll, ep, desc) =>
{
if (desc.InputParameters.Any(p => p.ParameterType == typeof(T)))
{
coll.Add(new ValidationHandler<T>(desc));
}
});
return conf;
}
so this methos checks if there is a T type parameter in the operations, and if so, it adds the handler to that specific operation.
This one calls the other extension method AddRequestHandler, and that method add the new handler without removing the previous registered ones, if the exist.
public static WebApiConfiguration AddRequestHandlers(
this WebApiConfiguration conf,
Action<Collection<HttpOperationHandler>,ServiceEndpoint,HttpOperationDescription> requestHandlerDelegate)
{
var old = conf.RequestHandlers;
conf.RequestHandlers = old == null ? requestHandlerDelegate :
(coll, ep, desc) =>
{
old(coll, ep, desc);
};
return conf;
}
The last thing is to register the handler:
var config = new WebApiConfiguration();
config.ModelValidationFor<T>(); //Instead of passing a T object pass the object you want to validate
routes.SetDefaultHttpConfiguration(config);
routes.MapServiceRoute<YourResourceObject>("SomeRoute");
So this is it.. Hope it helps somebody else!!
I am currently working on a HttpOperationHandler that does exactly what you need. It's not done by now, but this psuedo code might give you an idea of how you can do it.
public class ValidationHandler : HttpOperationHandler
{
private readonly HttpOperationDescription _httpOperationDescription;
private readonly Uri _baseAddress;
public ValidationHandler(HttpOperationDescription httpOperationDescription, Uri baseAddress)
{
_httpOperationDescription = httpOperationDescription;
_baseAddress = baseAddress;
}
protected override IEnumerable<HttpParameter> OnGetInputParameters()
{
return new[] { HttpParameter.RequestMessage };
}
protected override IEnumerable<HttpParameter> OnGetOutputParameters()
{
var types = _httpOperationDescription.InputParameters.Select(x => x.ParameterType);
return types.Select(type => new HttpParameter(type.Name, type));
}
protected override object[] OnHandle(object[] input)
{
var request = (HttpRequestMessage)input[0];
var uriTemplate = _httpOperationDescription.GetUriTemplate();
var uriTemplateMatch = uriTemplate.Match(_baseAddress, request.RequestUri);
var validationResults = new List<ValidationResult>();
//Bind the values from uriTemplateMatch.BoundVariables to a model
//Do the validation with Validator.TryValidateObject and add the results to validationResults
//Throw a exception with BadRequest http status code and add the validationResults to the message
//Return an object array with instances of the types returned from the OnGetOutputParmeters with the bounded values
}
}
The OnGetInputParameters value tells what's expected into the OnHandle method, and the OnGetOutputParameters tells what's the expected output from the OnHandle method (which later on is injected into the method in the service).
You can then add the handler to the routing with a HttpConfiguration as follows:
var httpConfiguration = new HttpConfiguration
{
RequestHandlers = (collection, endpoint, operation) => collection.Add(new ValidationHandler(operation, endpoint.Address.Uri))
};
RouteTable.Routes.MapServiceRoute<MyResource>("MyResource", httpConfiguration);
There is an example of this posted on MSDN of creating a behavior for this that should work. You could also call the validators manually with Validator.ValidateObject (or wrap it as an extension method) and return the validation errors, which is essentially what that behavior is doing.
Firstly I should say awesome question+answer Daniel
However, I've taken it a little further, refined it and added to it.
ValidationHander
I've refined this a little. It is now based on a generic HttpOperationHandler so it can take the HttpRequestMessage. The reason for this is so that I can return error messages formatted using the correct media type (from the accept header).
public class ValidationHandler<TResource> : HttpOperationHandler<TResource, HttpRequestMessage, HttpRequestMessage>
{
public ValidationHandler() : base("response") { }
protected override HttpRequestMessage OnHandle(TResource model, HttpRequestMessage requestMessage)
{
var results = new List<ValidationResult>();
var context = new ValidationContext(model, null, null);
Validator.TryValidateObject(model, context, results, true);
if (results.Count == 0)
{
return requestMessage;
}
var errorMessages = results.Select(x => x.ErrorMessage).ToArray();
var mediaType = requestMessage.Headers.Accept.FirstOrDefault();
var response = new RestValidationFailure(errorMessages);
if (mediaType != null)
{
response.Content = new ObjectContent(typeof (string[]), errorMessages, mediaType);
}
throw new HttpResponseException(response);
}
}
Extension Methods
The 2 you provided stay virtually the same about from the desc paramter no longer being needed when adding the ValidationHandler in the ModelValidationFor method
I've added an extra extension method. This is to make sure that all "Resource" classes are validated. This is mainly me being lazy and forgetful. I am forever forgetting to add some class to a list somewhere. (It's why I write generic windsor installers!)
public static void ValidateAllResourceTypes(this WebApiConfiguration config, string assemblyFilter = "MyCompany*.dll")
{
var path = Path.GetDirectoryName((new Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath);
var dc = new DirectoryCatalog(path, assemblyFilter);
var assemblies = dc.LoadedFiles.Select(Assembly.LoadFrom).ToList();
assemblies.ForEach(assembly =>
{
var resourceTypes = assembly.GetTypes()
.Where(t => t.Namespace != null && t.Namespace.EndsWith("Resources"));
foreach (var resourceType in resourceTypes)
{
var configType = typeof(Extensions);
var mi = configType.GetMethod("ModelValidationFor");
var mi2 = mi.MakeGenericMethod(resourceType);
mi2.Invoke(null, new object[] { config });
}
});
}
I made use of the System.ComponentModel.Composition.Hosting namespace (formerly known as MEF) for the DirectoryCatalog class. In this case I've just used the namespace ending with "Resources" to find my "Resource" classes. It wouldn't take much work to change it to use a custom attribute or whatever other way you might prefer to identify which classes are your "Resources".
RestValidationFailure
This is a little helper class I made to allow consistent behaviour for validation failure responses.
public class RestValidationFailure : HttpResponseMessage
{
public RestValidationFailure(string[] messages)
{
StatusCode = HttpStatusCode.BadRequest;
foreach (var errorMessage in messages)
{
Headers.Add("X-Validation-Error", errorMessage);
}
}
}
So, now I get a nice list (in my preferred mediatype) of all the validation errors.
Enjoy! :)

Categories

Resources