I'm using NET5 webapi with HotChocolate package and am trying to inject a service.
I've followed both standard and method based approach documented here however it doesn't work at all. All i get is the following message:
{
"errors": [
{
"message": "Unexpected Execution Error",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"tests"
]
}
],
"data": {
"tests": null
}
}
My query:
query{
tests {
id
}
}
My code currently reflects the method approach as documented.
In startup:
services
.AddSingleton<ITestService, TestService>()
.AddGraphQLServer()
.AddDefaultTransactionScopeHandler()
.AddQueryType<Queries>()
.AddMutationType<Mutations>()
.AddFiltering()
.AddSorting()
.AddProjections()
.AddType<Test>();
The query setup:
[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<Test> GetTests([Service] ITestService testService) => testService.GetTests();
My TestService:
private readonly IDbContextFactory<TestDbContext> contextFactory;
public TestService(IDbContextFactory<TestDbContext> contextFactory)
{
this.contextFactory = contextFactory;
}
public IQueryable<Test> GetTests()
{
using var context = contextFactory.CreateDbContext();
return context.Test;
}
I'm sure I'm missing something simple to make this work.
Your DB Context is disposed. The using in GetTests is scoped for this method. On the end of this method the db context gets disposed and a Queryable is returned. Once the execution engine executes the Queryable, the exception is thrown
Checkout the EF Core integration of HotChocolate:
https://chillicream.com/docs/hotchocolate/integrations/entity-framework
Related
I have implemented Audit Trail in asp.net core 3.1 application using great library which has a very good documentation also : https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.WebApi/README.md
I have implemented it in a asp.net core 3.1 web api project with the recommended approach : Middleware + Action Filters (Asp.Net Core): Adding the Audit Middleware together with the Global Action Filter (or Local Action Filters).
I have the following sample output:
{
"EventType":"POST Values/Post",
"Environment":{
"UserName":"Federico",
"MachineName":"HP",
"DomainName":"HP",
"CallingMethodName":"WebApiTest.Controllers.ValuesController.Post()",
"AssemblyName":"WebApiTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"Culture":"en-US"
},
"StartDate":"2017-03-09T18:03:05.5287603-06:00",
"EndDate":"2017-03-09T18:03:05.5307604-06:00",
"Duration":2,
"Action":{
"TraceId": "0HLFLQP4HGFAF_00000001",
"HttpMethod":"POST",
"ControllerName":"Values",
"ActionName":"Post",
"ActionParameters":{
"value":{
"Id":100,
"Text":"Test"
}
},
"FormVariables":{
},
"RequestUrl":"http://localhost:65080/api/values",
"IpAddress":"127.0.0.1",
"ResponseStatus":"OK",
"ResponseStatusCode":200,
"RequestBody":{
"Type":"application/json",
"Length":27,
"Value":"{ Id: 100, Text: \"Test\" }"
},
"ResponseBody":{
"Type":"SomeObject",
"Value":{
"Id":1795824380,
"Text":"Test"
}
},
"Headers": {
"Connection": "Keep-Alive",
"Accept": "text/html, application/xhtml+xml, image/jxr, */*",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-GB",
"Host": "localhost:37341",
"User-Agent": "Mozilla/5.0, (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0), like, Gecko"
}
}
}
From the above output I want ActionParameters not to be captured as part of the Audit trail data. I have gone through the documentation but did not see any out of the box solution for it.
Can anyone help me here with some code sample which will serve as a reference for my implementation
There are at least three ways to accomplish this.
You can avoid the parameters being captured in the event object by marking those with [AuditIgnore] Attribute in the action method.
[HttpPost]
public IEnumerable<string> PostAccount(string user, [AuditIgnore]string password)
{
// password argument will not be audited
}
Or you can remove the action parameters from the event object before saving the scope, by using a custom action:
// On your start-up code
using Audit.WebApi;
Audit.Core.Configuration.AddCustomAction(ActionType.OnEventSaving, scope =>
{
scope.GetWebApiAuditAction().ActionParameters = null;
});
Or, as ChatGPT suggested, you could implement your own AuditDataProvider, inheriting from the Data Provider you currently use, and removing the Action Parameters before calling the real provider's InsertEvent/ReplaceEvent methods. But this complicates things unnecessarily.
public class CustomAuditDataProvider : Audit.Core.Providers.FileDataProvider
{
public override object InsertEvent(AuditEvent auditEvent)
{
RemoveActionParams(auditEvent);
return base.InsertEvent(auditEvent);
}
public override Task<object> InsertEventAsync(AuditEvent auditEvent)
{
RemoveActionParams(auditEvent);
return base.InsertEventAsync(auditEvent);
}
public override void ReplaceEvent(object path, AuditEvent auditEvent)
{
RemoveActionParams(auditEvent);
base.ReplaceEvent(path, auditEvent);
}
public override Task ReplaceEventAsync(object path, AuditEvent auditEvent)
{
RemoveActionParams(auditEvent);
return base.ReplaceEventAsync(path, auditEvent);
}
private void RemoveActionParams(AuditEvent auditEvent)
{
auditEvent.GetWebApiAuditAction().ActionParameters = null;
}
}
// In your start-up code:
Audit.Core.Configuration.Setup().UseCustomProvider(new CustomAuditDataProvider());
I'm using OData with ASP.NET Core to work with Oracle database. I have a Startup.cs file where I configure authentication, build the model and load all dependencies. I am also reading a config file to load custom odata controllers identified like this :
CustomControllerList": [
{
"Assembly": "assemblyName",
"PublicToken" : "123456789",
"Controller": "UsersController",
"Name": "Users",
"Entity": "ModelNameSpace.UserEntity",
"AccessRights" : [1, 2, 3]
},
{
"Assembly": "assemblyName",
"PublicToken" : "123456789",
"Controller": "GroupsController",
"Name": "Users",
"Entity": "ModelNameSpace.GroupsEntity",
"AccessRights" : [4, 5, 6]
}]
I would like to store access rights related to a controller in order to check before each request if user is authorized.
Concerning code execution before each request, I saw that creating a new controller's functions attribute like this
public class AccessRightsFilterAttribute : Attribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
try
{
String username = Tools.GetUsernameFromToken(context.Controller as ControllerBase);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
// do something after the action executes
}
}
My first question is : Is this the only one solution for executing code before each request ? Is there a way to avoid having to put attribute for every OData controller's functions ?
I can't connect to db inside Startup execution and custom OData controllers are not able to access the Startup project.
So my second question is : What is the best practice for reading this data from OData controllers ? I didn't found anything, my only choice is to write inside a file but I would like to know if there is a better way to do it.
Thanks in advance !
I am:
deploying a C# app to Lambda to the first time.
using Mac so can't use the Visual Studio AWS Toolkit Extension.
using C# .NET core 3.1.
deploying using: dotnet lambda deploy-serverless
The deployment seems to work without errors, the Lambda is visible in the AWS Console.
When I test the Lambda from AWS Console log output is generated, some of which is from my C# code. Such as this line "LambdaEntryPoint - init".
However none of the log output in my handler (FunctionHandlerZ) is written to the log.
I see this exception when I use the AWS Console Test facility:
{
"errorType": "NullReferenceException",
"errorMessage": "Object reference not set to an instance of an object.",
"stackTrace": [
"at Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction.MarshallRequest(InvokeFeatures features, APIGatewayProxyRequest apiGatewayRequest, ILambdaContext lambdaContext)",
"at Amazon.Lambda.AspNetCoreServer.AbstractAspNetCoreFunction`2.FunctionHandlerAsync(TREQUEST request, ILambdaContext lambdaContext)",
"at Amazon.Lambda.RuntimeSupport.HandlerWrapper.<>c__DisplayClass25_0`2.<<GetHandlerWrapper>b__0>d.MoveNext()",
"--- End of stack trace from previous location where exception was thrown ---",
"at Amazon.Lambda.RuntimeSupport.LambdaBootstrap.InvokeOnceAsync(CancellationToken cancellationToken)"
]
}
LambdaEntryPoint.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using Amazon.Lambda.Core;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace aspDemo3B
{
public class LambdaEntryPoint :
// When using an ELB's Application Load Balancer as the event source change
// the base class to Amazon.Lambda.AspNetCoreServer.ApplicationLoadBalancerFunction
Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction
{
/// <summary>
/// The builder has configuration, logging and Amazon API Gateway already configured. The startup class
/// needs to be configured in this method using the UseStartup<>() method.
/// </summary>
/// <param name="builder"></param>
protected override void Init(IWebHostBuilder builder)
{
Console.WriteLine("LambdaEntryPoint - init");
builder
.UseStartup<Startup>();
}
public string FunctionHandlerZ(string input, ILambdaContext context)
{
Console.WriteLine("FunctionHandlerZ");
Console.WriteLine($"Calling function name: {context.FunctionName}\\n");
return input?.ToUpper();
}
}
}
serverless.template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::Serverless-2016-10-31",
"Description": "An AWS Serverless Application that uses the ASP.NET Core framework running in Amazon Lambda.",
"Parameters": {},
"Conditions": {},
"Resources": {
"AspNetCoreFunction": {
"Type": "AWS::Serverless::Function",
"Properties": {
"Handler": "aspDemo3B::aspDemo3B.LambdaEntryPoint:FunctionHandlerZ",
"Runtime": "dotnetcore3.1",
"CodeUri": "",
"MemorySize": 256,
"Timeout": 30,
"Role": null,
"Policies": [
"AWSLambdaFullAccess"
],
"Environment": {
"Variables": {
"LAMBDA_NET_SERIALIZER_DEBUG": "true"
}
},
"Events": {
"ProxyResource": {
"Type": "Api",
"Properties": {
"Path": "/{proxy+}",
"Method": "ANY"
}
},
"RootResource": {
"Type": "Api",
"Properties": {
"Path": "/",
"Method": "ANY"
}
}
}
}
}
},
"Outputs": {
"ApiURL": {
"Description": "API endpoint URL for Prod environment",
"Value": {
"Fn::Sub": "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
}
}
}
}
I am happy to start from scratch with a simple helloWorld style Lambda that:
Does not require AWS Toolkit Extension, as it is not available on Mac.
Uses .NET core 3.1 (there have been some changes from 3.0 to 3.1 for AWS Lambda)
Is initiated by a HTTP request via API GW and returns a simple response
Below is will help you
public class LambdaFunctionHandler : APIGatewayProxyFunction
{
protected override void Init(IWebHostBuilder builder)
{
builder.UseStartup<Startup>();
// DemoWebApi::DemoWebApi.ALBLambdaFunction::FunctionHandlerAsync
}
}
not required FunctionHandlerZ function
For any Lambda API you are using API Gateway FunctionHandlerAsync will be the entry point.
Lambda Function Handler should be as [AssemblyName]::[NameSpace].[Classname]::FunctionHandlerAsync
I have followed this tutorial while creating an API and come across an issue I struggle to solve:
I have two model-classes: Todo and TodoItem.
I have put an ICollection of TodoItems inside the Todo-class.
When I am to return the Todo's from an API GET request, it works the first time but as soon as a second request is sent, the TodoItem collection is overwritten and declared once more through the constructor of Todo.
Tried some annotations (ForeignKey).
Adding a list of TodoItemIds inside Todo
(TodoItemIds type = new class with Id and the TodoItemId).
Storing Todo and TodoId inside of TodoItem.
Tried to add some code to OnModelcreating() in TodoContext (modelBuilder.Entity<>()...).
Here is the controller code, I don't know how to paste it in nicely...:
TodoController
public TodoController(TodoContext context){
_context = context;
if (_context.TodoItems.Count() == 0)
{
// Create a new TodoItem if collection is empty,
// which means you can't delete all TodoItems.
_context.Todos.Add(new Todo(new TodoItem("Walk the dog")));
_context.SaveChanges();
}
}
// GET: api/Todo
[HttpGet]
public async Task<ActionResult<List<Todo>>> GetTodo()
{
return await _context.Todos.ToListAsync();
}
TodoContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Todo>()
.HasMany(t => t.TodoItems);
base.OnModelCreating(modelBuilder);
}
First Get-Request-Response
[
{
"id": "34bfd453-8f06-4733-a4b6-1fb209327a8d",
"todoItems": [
{
"id": 1,
"name": "Walk the dog",
"isComplete": false,
"todoId": "34bfd453-8f06-4733-a4b6-1fb209327a8d"
}
]
}
]
Second Get-Request-Response
[
{
"id": "34bfd453-8f06-4733-a4b6-1fb209327a8d",
"todoItems": []
}
]
The todoItems-list should not disappear.
You need to load Todo.TodoItems from the database.
[HttpGet]
public async Task<ActionResult<List<Todo>>> GetTodo()
{
return await _context.Todos.Include(t => t.TodoItems).ToListAsync();
}
Above code uses Eager Loading, Include(t => t.TodoItems), but there are different ways to load related data using EF Core.
The reason there's a TodoItem the first time is because it was just added to the TodoContext so it is still loaded on that particular TodoContext instance.
I am working on reading data from Table Storage in my Azure Function. I have created HttpTrigger function with in Table Storage binding. Project is using storage package:
"WindowsAzure.Storage": "8.0.0"
and binding:
{
"bindings": [
{
"authLevel": "anonymous",
"name": "req",
"type": "httpTrigger",
"direction": "in"
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"name": "metadataTable",
"type": "table",
"direction": "in",
"tableName": "metadata",
"connection": "StorageConnectionString",
"partitionkey": "some_partition_key"
}
],
"disabled": false
}
Having code generated by template I have added new in parameter:
#r "Microsoft.WindowsAzure.Storage"
using System;
using System.Net;
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.WindowsAzure.Storage;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req,
IQueryable<MetadataTable> metadataTable, TraceWriter log)
{
.....
}
public class MetadataTable: TableEntity
{
public MetadataTable():base() { }
public MetadataTable(string partitionkey, string rowkey):base(partitionkey,rowkey) {}
public string Data { get; set; }
}
During save and run process I am getting compile error:
Microsoft.Azure.WebJobs.Host: Error indexing method
'Functions.HttpTriggerCSharp1'. Microsoft.Azure.WebJobs.Host:
GenericArguments[0], 'Submission#0+MetadataTable', on
'Microsoft.Azure.WebJobs.Host.Tables.TableAttributeBindingProvider+TableToIQueryableConverter1[TElement]'
violates the constraint of type 'TElement'. mscorlib:
GenericArguments[0], 'Submission#0+MetadataTable', on
'Microsoft.Azure.WebJobs.Host.Tables.TableAttributeBindingProvider+TableToIQueryableConverter1[TElement]'
violates the constraint of type parameter 'TElement'.
Can anyone help me with this or meet same error?
The error message looks a bit weird, but try removing WindowsAzure.Storage reference from project.json file. This package is referenced automatically by the runtime, and if you include it explicitly you get all kinds of errors due to version mismatch.
I created a clean Azure Function from your code without the package reference and it compiled and worked just fine. Try the same.