Skip to content

Instantly share code, notes, and snippets.

@Pzixel
Last active April 20, 2022 15:10
Show Gist options
  • Save Pzixel/cf09ca4f360356d8749a9fe2049d3169 to your computer and use it in GitHub Desktop.
Save Pzixel/cf09ca4f360356d8749a9fe2049d3169 to your computer and use it in GitHub Desktop.
using System;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Extensions;
using Microsoft.AspNet.OData.Formatter;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
using Microsoft.OData.Edm;
using Microsoft.OData.UriParser;
namespace My
{
public static class XOdataStartup
{
public static IServiceCollection RegisterOData(this IServiceCollection services)
{
services.AddOData();
// fix invalid OData media type: https://github.com/OData/WebApi/issues/2024
// multiple "AddMvcCore" calls are ok
services.AddMvcCore(options =>
{
foreach (var outputFormatter in options.OutputFormatters.OfType<ODataOutputFormatter>()
.Where(x => x.SupportedMediaTypes.Count == 0))
{
outputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/prs.odatatestxx-odata"));
}
foreach (var inputFormatter in options.InputFormatters.OfType<ODataInputFormatter>()
.Where(x => x.SupportedMediaTypes.Count == 0))
{
inputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/prs.odatatestxx-odata"));
}
});
return services;
}
public static IApplicationBuilder UseMvcWithOData(this IApplicationBuilder app,
string routePrefix,
Action<ODataConventionModelBuilder> builderConfigurator,
params Delegate[] customFunctions)
{
var odataModelBuilder = GetOdataBuilder(app, builderConfigurator, customFunctions);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints
.SetTimeZoneInfo(TimeZoneInfo.Utc)
.Select()
.Expand()
.Filter()
.OrderBy()
.MaxTop(null)
.Count();
endpoints.MapODataRoute("ODataRoute", routePrefix, odataModelBuilder.GetEdmModel());
});
return app;
}
private static ODataConventionModelBuilder GetOdataBuilder(IApplicationBuilder app,
Action<ODataConventionModelBuilder> builderConfigurator,
params Delegate[] customFunctions)
{
var builder = new ODataConventionModelBuilder(app.ApplicationServices);
builderConfigurator(builder);
foreach (var customFunction in customFunctions)
{
RegisterCustomFunction(customFunction);
}
return builder;
}
public static ODataConventionModelBuilder AddEntity<T, TKey>(this ODataConventionModelBuilder builder, Expression<Func<T, TKey>> keyDefinitionExpression)
where T : class
{
var entity = builder.EntitySet<T>(typeof(T).Name.ToLower());
entity.EntityType.HasKey(keyDefinitionExpression);
return builder;
}
private static void RegisterCustomFunction(Delegate method)
{
var methodInfo = method.Method;
var returnType = TypeToReference(methodInfo.ReturnType);
var args = methodInfo.GetParameters()
.Select(x => TypeToReference(x.ParameterType))
.ToArray();
var signature = new FunctionSignatureWithReturnType(returnType, args);
ODataUriFunctions.AddCustomUriFunction(methodInfo.Name, signature, methodInfo);
}
private static IEdmTypeReference TypeToReference(Type type)
{
var primitiveTypeKind = EdmCoreModel.Instance.GetPrimitiveTypeKind(type.Name);
var isNullable = type.IsClass || Nullable.GetUnderlyingType(type) != null;
return new EdmPrimitiveTypeReference(
EdmCoreModel.Instance.GetPrimitiveType(primitiveTypeKind),
isNullable);
}
}
}
public static IApplicationBuilder UseMvcWithOData(this IApplicationBuilder app) =>
app.UseMvcWithOData($"{ApiConstant.Prefix}odata",
builder =>
{
builder
.AddMyEntity<Order>()
},
new Func<string, string, bool>(CustomFunctions.ContainsIgnoreCase),
new Func<string, string, bool>(CustomFunctions.StartsWithIgnoreCase));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment