HeavenVR
Roslyn Incremental CodeGen from text files not working
I wrote this codegen dll for internal use in the project, but i cannot reference the generated source code in the "CodeGen" project
Referencing it from "Common" project:
The "CodeGen" csproj:
The codegen source:
<Project Sdk="Microsoft.NET.Sdk.Web">
...
<ItemGroup>
<ProjectReference Include="..\CodeGen\CodeGen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk.Web">
...
<ItemGroup>
<ProjectReference Include="..\CodeGen\CodeGen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../Shared.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="../cloudflare-ips-v4.txt" />
<AdditionalFiles Include="../cloudflare-ips-v6.txt" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../Shared.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="../cloudflare-ips-v4.txt" />
<AdditionalFiles Include="../cloudflare-ips-v6.txt" />
</ItemGroup>
</Project>
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System.Text;
namespace OpenShock.CodeGen;
[Generator]
internal class CloudflareProxiesGenerator : IIncrementalGenerator
{
private const string IpV4Name = "cloudflare-ips-v4.txt";
private const string IpV6Name = "cloudflare-ips-v6.txt";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var additionalFiles = context.AdditionalTextsProvider
.Where(file => file.Path.EndsWith(IpV4Name) || file.Path.EndsWith(IpV6Name))
.Collect();
context.RegisterSourceOutput(additionalFiles, (ctx, files) =>
{
var ipv4Lines = files.FirstOrDefault(f => f.Path.EndsWith(IpV4Name))?.GetText()?.Lines.Select(l => l.ToString().Trim()).Where(l => !string.IsNullOrEmpty(l)) ?? [];
var ipv6Lines = files.FirstOrDefault(f => f.Path.EndsWith(IpV6Name))?.GetText()?.Lines.Select(l => l.ToString().Trim()).Where(l => !string.IsNullOrEmpty(l)) ?? [];
var sourceBuilder = new StringBuilder();
sourceBuilder.AppendLine("using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;");
sourceBuilder.AppendLine();
sourceBuilder.AppendLine("namespace OpenShock;");
sourceBuilder.AppendLine();
sourceBuilder.AppendLine("public static class CloudflareProxies");
sourceBuilder.AppendLine("{");
sourceBuilder.AppendLine(" public static readonly IPNetwork[] PrefetchedCloudflareProxies = [");
sourceBuilder.AppendLine(" // IPv4");
foreach (var line in ipv4Lines)
sourceBuilder.AppendLine($" IPNetwork.Parse(\"{line}\"),");
sourceBuilder.AppendLine("\n // IPv6");
foreach (var line in ipv6Lines)
sourceBuilder.AppendLine($" IPNetwork.Parse(\"{line}\"),");
sourceBuilder.AppendLine(" ];");
sourceBuilder.AppendLine("}");
ctx.AddSource("CloudflareProxies.g.cs", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
});
}
}
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System.Text;
namespace OpenShock.CodeGen;
[Generator]
internal class CloudflareProxiesGenerator : IIncrementalGenerator
{
private const string IpV4Name = "cloudflare-ips-v4.txt";
private const string IpV6Name = "cloudflare-ips-v6.txt";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var additionalFiles = context.AdditionalTextsProvider
.Where(file => file.Path.EndsWith(IpV4Name) || file.Path.EndsWith(IpV6Name))
.Collect();
context.RegisterSourceOutput(additionalFiles, (ctx, files) =>
{
var ipv4Lines = files.FirstOrDefault(f => f.Path.EndsWith(IpV4Name))?.GetText()?.Lines.Select(l => l.ToString().Trim()).Where(l => !string.IsNullOrEmpty(l)) ?? [];
var ipv6Lines = files.FirstOrDefault(f => f.Path.EndsWith(IpV6Name))?.GetText()?.Lines.Select(l => l.ToString().Trim()).Where(l => !string.IsNullOrEmpty(l)) ?? [];
var sourceBuilder = new StringBuilder();
sourceBuilder.AppendLine("using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;");
sourceBuilder.AppendLine();
sourceBuilder.AppendLine("namespace OpenShock;");
sourceBuilder.AppendLine();
sourceBuilder.AppendLine("public static class CloudflareProxies");
sourceBuilder.AppendLine("{");
sourceBuilder.AppendLine(" public static readonly IPNetwork[] PrefetchedCloudflareProxies = [");
sourceBuilder.AppendLine(" // IPv4");
foreach (var line in ipv4Lines)
sourceBuilder.AppendLine($" IPNetwork.Parse(\"{line}\"),");
sourceBuilder.AppendLine("\n // IPv6");
foreach (var line in ipv6Lines)
sourceBuilder.AppendLine($" IPNetwork.Parse(\"{line}\"),");
sourceBuilder.AppendLine(" ];");
sourceBuilder.AppendLine("}");
ctx.AddSource("CloudflareProxies.g.cs", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
});
}
}
32 replies
✅ Microsoft.AspNetCore.OpenApi possible bug with valuetypes
I get this exception whenever i try having a baseresponse of type
Guid
or an enum type.
The example endpoint can be annotated with:
[ProducesResponseType<MyResponseWrapperClass<Guid>>(StatusCodes.Status200OK, MediaTypeNames.Application.Json)]
this will cause an exception on generating the openapi docs:
System.Text.Json.JsonException: The JSON value could not be converted to System.Guid.
at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType)
at System.Text.Json.JsonSerializer.UnboxOnWrite[T](Object value)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsObject(Utf8JsonWriter writer, Object rootValue)
at System.Text.Json.JsonSerializer.WriteNodeAsObject(Object value, JsonTypeInfo jsonTypeInfo)
at System.Text.Json.Schema.JsonSchemaExporter.MapJsonSchemaCore(GenerationState& state, JsonTypeInfo typeInfo, JsonPropertyInfo propertyInfo, JsonConverter customConverter, Nullable`1 customNumberHandling, JsonTypeInfo parentPolymorphicTypeInfo, Boolean parentPolymorphicTypeContainsTypesWithoutDiscriminator, Boolean parentPolymorphicTypeIsNonNullable, Nullable`1 typeDiscriminator, Boolean cacheResult)
at System.Text.Json.Schema.JsonSchemaExporter.GetJsonSchemaAsNode(JsonTypeInfo typeInfo, JsonSchemaExporterOptions exporterOptions)
at System.Text.Json.Schema.JsonSchemaExporter.GetJsonSchemaAsNode(JsonSerializerOptions options, Type type, JsonSchemaExporterOptions exporterOptions)
at Microsoft.AspNetCore.OpenApi.OpenApiSchemaService.CreateSchema(OpenApiSchemaKey key)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.AspNetCore.OpenApi.OpenApiSchemaStore.GetOrAdd(OpenApiSchemaKey key, Func`2 valueFactory)
at Microsoft.AspNetCore.OpenApi.OpenApiSchemaService.GetOrCreateSchemaAsync(Type type, IServiceProvider scopedServiceProvider, IOpenApiSchemaTransformer[] schemaTransformers, ApiParameterDescription parameterDescription, Boolean captureSchemaByRef, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetResponseAsync(ApiDescription apiDescription, Int32 statusCode, ApiResponseType apiResponseType, IServiceProvider scopedServiceProvider, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetResponsesAsync(ApiDescription description, IServiceProvider scopedServiceProvider, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOperationAsync(ApiDescription description, HashSet`1 capturedTags, IServiceProvider scopedServiceProvider, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOperationsAsync(IGrouping`2 descriptions, HashSet`1 capturedTags, IServiceProvider scopedServiceProvider, IOpenApiOperationTransformer[] operationTransformers, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiPathsAsync(HashSet`1 capturedTags, IServiceProvider scopedServiceProvider, IOpenApiOperationTransformer[] operationTransformers, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiDocumentAsync(IServiceProvider scopedServiceProvider, HttpRequest httpRequest, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Builder.OpenApiEndpointRouteBuilderExtensions.<>c__DisplayClass0_0.<<MapOpenApi>b__0>d.MoveNext()
System.Text.Json.JsonException: The JSON value could not be converted to System.Guid.
at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType)
at System.Text.Json.JsonSerializer.UnboxOnWrite[T](Object value)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsObject(Utf8JsonWriter writer, Object rootValue)
at System.Text.Json.JsonSerializer.WriteNodeAsObject(Object value, JsonTypeInfo jsonTypeInfo)
at System.Text.Json.Schema.JsonSchemaExporter.MapJsonSchemaCore(GenerationState& state, JsonTypeInfo typeInfo, JsonPropertyInfo propertyInfo, JsonConverter customConverter, Nullable`1 customNumberHandling, JsonTypeInfo parentPolymorphicTypeInfo, Boolean parentPolymorphicTypeContainsTypesWithoutDiscriminator, Boolean parentPolymorphicTypeIsNonNullable, Nullable`1 typeDiscriminator, Boolean cacheResult)
at System.Text.Json.Schema.JsonSchemaExporter.GetJsonSchemaAsNode(JsonTypeInfo typeInfo, JsonSchemaExporterOptions exporterOptions)
at System.Text.Json.Schema.JsonSchemaExporter.GetJsonSchemaAsNode(JsonSerializerOptions options, Type type, JsonSchemaExporterOptions exporterOptions)
at Microsoft.AspNetCore.OpenApi.OpenApiSchemaService.CreateSchema(OpenApiSchemaKey key)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.AspNetCore.OpenApi.OpenApiSchemaStore.GetOrAdd(OpenApiSchemaKey key, Func`2 valueFactory)
at Microsoft.AspNetCore.OpenApi.OpenApiSchemaService.GetOrCreateSchemaAsync(Type type, IServiceProvider scopedServiceProvider, IOpenApiSchemaTransformer[] schemaTransformers, ApiParameterDescription parameterDescription, Boolean captureSchemaByRef, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetResponseAsync(ApiDescription apiDescription, Int32 statusCode, ApiResponseType apiResponseType, IServiceProvider scopedServiceProvider, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetResponsesAsync(ApiDescription description, IServiceProvider scopedServiceProvider, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOperationAsync(ApiDescription description, HashSet`1 capturedTags, IServiceProvider scopedServiceProvider, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOperationsAsync(IGrouping`2 descriptions, HashSet`1 capturedTags, IServiceProvider scopedServiceProvider, IOpenApiOperationTransformer[] operationTransformers, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiPathsAsync(HashSet`1 capturedTags, IServiceProvider scopedServiceProvider, IOpenApiOperationTransformer[] operationTransformers, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiDocumentAsync(IServiceProvider scopedServiceProvider, HttpRequest httpRequest, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Builder.OpenApiEndpointRouteBuilderExtensions.<>c__DisplayClass0_0.<<MapOpenApi>b__0>d.MoveNext()
2 replies
Is there a better way to write this QueryBuilder?
Its my first time writing one and i want to make sure im doing it right
public static class IQueryableExtensions
{
private static Expression<Func<TEntity, bool>> EntityPropExpr<TEntity>(Expression navigationSelector, Func<InvocationExpression, BinaryExpression> binaryExpressionGetter)
{
// Create a parameter for TEntity (entity)
var entityParameter = Expression.Parameter(typeof(TEntity), "entity");
// Access the prop from the navigation selector
var entityExpression = Expression.Invoke(navigationSelector, entityParameter);
var binaryExpression = binaryExpressionGetter(entityExpression);
// Build the lambda expression
return Expression.Lambda<Func<TEntity, bool>>(binaryExpression, entityParameter);
}
private static BinaryExpression UserIdMatchesExpr(InvocationExpression userExpression, Guid userId)
{
return Expression.Equal(
Expression.Property(userExpression, nameof(OpenShockDb.User.Id)),
Expression.Constant(userId)
);
}
private static Expression<Func<TEntity, bool>> IsUserMatchExpr<TEntity>(Expression navigationSelector, Guid userId)
{
return EntityPropExpr<TEntity>(navigationSelector, user => UserIdMatchesExpr(user, userId));
}
public static IQueryable<TEntity> WhereIsUser<TEntity>(this IQueryable<TEntity> source, Expression navigationSelector, Guid userId)
{
return source.Where(IsUserMatchExpr<TEntity>(navigationSelector, userId));
}
}
public static class IQueryableExtensions
{
private static Expression<Func<TEntity, bool>> EntityPropExpr<TEntity>(Expression navigationSelector, Func<InvocationExpression, BinaryExpression> binaryExpressionGetter)
{
// Create a parameter for TEntity (entity)
var entityParameter = Expression.Parameter(typeof(TEntity), "entity");
// Access the prop from the navigation selector
var entityExpression = Expression.Invoke(navigationSelector, entityParameter);
var binaryExpression = binaryExpressionGetter(entityExpression);
// Build the lambda expression
return Expression.Lambda<Func<TEntity, bool>>(binaryExpression, entityParameter);
}
private static BinaryExpression UserIdMatchesExpr(InvocationExpression userExpression, Guid userId)
{
return Expression.Equal(
Expression.Property(userExpression, nameof(OpenShockDb.User.Id)),
Expression.Constant(userId)
);
}
private static Expression<Func<TEntity, bool>> IsUserMatchExpr<TEntity>(Expression navigationSelector, Guid userId)
{
return EntityPropExpr<TEntity>(navigationSelector, user => UserIdMatchesExpr(user, userId));
}
public static IQueryable<TEntity> WhereIsUser<TEntity>(this IQueryable<TEntity> source, Expression navigationSelector, Guid userId)
{
return source.Where(IsUserMatchExpr<TEntity>(navigationSelector, userId));
}
}
6 replies