Skip to content

Restier cannot handle more than one API registered per app. #527

@robertmclaws

Description

@robertmclaws

It appears that the design for Restier did not take into account the possibility that more than one API could be registered with inside a single project.

Assemblies affected

RESTier 1.0.0-beta

Reproduce steps

Register 2 APIs in a single project using MapRestierRoute.

Expected result

I would expect a request to the service to return normally.

Actual result

The Dependency Injection system is throwing an error because there is more than one model registered, but the call is apparently calling the LINQ .Single() function, which only expects one element. It should likely be calling .FirstOrDefault() instead and checking for a null result.

{
  "Message": "An error has occurred.",
  "ExceptionMessage": "One or more errors occurred.",
  "ExceptionType": "System.AggregateException",
  "StackTrace": "   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)\r\n   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)\r\n   at System.Threading.Tasks.Task`1.get_Result()\r\n   at Microsoft.Restier.Core.RestierContainerBuilder.<AddRestierService>b__0(IServiceProvider sp)\r\n   at Microsoft.Extensions.DependencyInjection.ServiceLookup.FactoryService.Invoke(ServiceProvider provider)\r\n   at Microsoft.Extensions.DependencyInjection.ServiceProvider.ScopedCallSite.Invoke(ServiceProvider provider)\r\n   at Microsoft.Extensions.DependencyInjection.ServiceProvider.SingletonCallSite.Invoke(ServiceProvider provider)\r\n   at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass12_0.<RealizeService>b__0(ServiceProvider provider)\r\n   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)\r\n   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)\r\n   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)\r\n   at System.Web.OData.Routing.DefaultODataPathHandler.Parse(String serviceRoot, String odataPath, IServiceProvider requestContainer, Boolean template)\r\n   at System.Web.OData.Routing.DefaultODataPathHandler.Parse(String serviceRoot, String odataPath, IServiceProvider requestContainer)\r\n   at System.Web.OData.Routing.ODataPathRouteConstraint.Match(HttpRequestMessage request, IHttpRoute route, String parameterName, IDictionary`2 values, HttpRouteDirection routeDirection)\r\n   at System.Web.Http.Routing.HttpRoute.ProcessConstraint(HttpRequestMessage request, Object constraint, String parameterName, HttpRouteValueDictionary values, HttpRouteDirection routeDirection)\r\n   at System.Web.Http.Routing.HttpRoute.ProcessConstraints(HttpRequestMessage request, HttpRouteValueDictionary values, HttpRouteDirection routeDirection)\r\n   at System.Web.Http.Routing.HttpRoute.GetRouteData(String virtualPathRoot, HttpRequestMessage request)\r\n   at System.Web.Http.WebHost.Routing.HttpWebRoute.GetRouteData(HttpContextBase httpContext)",
  "InnerException": {
    "Message": "An error has occurred.",
    "ExceptionMessage": "Sequence contains more than one element",
    "ExceptionType": "System.InvalidOperationException",
    "StackTrace": "   at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)\r\n   at Microsoft.Restier.Providers.EntityFramework.ModelProducer.GetModelAsync(ModelContext context, CancellationToken cancellationToken)\r\n   at Microsoft.Restier.Publishers.OData.Model.RestierModelBuilder.<GetModelAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at Microsoft.Restier.Publishers.OData.Model.RestierModelExtender.ModelBuilder.<GetModelReturnedByInnerHandlerAsync>d__17.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at Microsoft.Restier.Publishers.OData.Model.RestierModelExtender.ModelBuilder.<GetModelAsync>d__12.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at Microsoft.Restier.Publishers.OData.Model.RestierOperationModelBuilder.<GetModelAsync>d__4.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at Microsoft.Restier.Core.ApiBaseExtensions.<GetModelAsync>d__0.MoveNext()"
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions