Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6bba55b
[FEATURE]: Add Support for IEnumerable Yield (#62)
github-actions[bot] Mar 28, 2025
a8b524c
Renamed some of the class to reflect being Enumerable vs yield
MattEdwardsWaggleBee Mar 28, 2025
19f0b87
clean up and simplify documentation
MattEdwardsWaggleBee Mar 31, 2025
e489cc8
Fix issue with preferInterpretation
MattEdwardsWaggleBee Mar 31, 2025
d0107bf
clean up
MattEdwardsWaggleBee Mar 31, 2025
86535ce
Clean up test and submit bug to dotnet/runtime
MattEdwardsWaggleBee Mar 31, 2025
fc844b1
Previous version was 'v1.1.4'. Version now 'v1.1.5'.
MattEdwardsWaggleBee Mar 31, 2025
578afea
[FEATURE]: Add Support for Dependency Injection and Configuration (#67)
github-actions[bot] Apr 1, 2025
504145b
updates for passing type
MattEdwardsWaggleBee Apr 2, 2025
fa1d442
Updated code formatting to match rules in .editorconfig
invalid-email-address Apr 2, 2025
298f513
Expose properties for Inject and Config
MattEdwardsWaggleBee Apr 2, 2025
2caf285
Add Delegate based service provider Compile
MattEdwardsWaggleBee Apr 2, 2025
0497302
update readme
MattEdwardsWaggleBee Apr 2, 2025
e39b4ec
Merge branch 'main' into develop
MattEdwardsWaggleBee Apr 2, 2025
0bb245c
Merge branch 'main' into develop
MattEdwardsWaggleBee Apr 3, 2025
6e57095
Updated code formatting to match rules in .editorconfig
invalid-email-address Apr 3, 2025
c0d0304
Merge branch 'main' into develop
MattEdwardsWaggleBee Apr 3, 2025
8bb4c5d
Merge branch 'main' into develop
MattEdwardsWaggleBee Apr 10, 2025
86818a3
Merge branch 'main' into develop
MattEdwardsWaggleBee Apr 15, 2025
948eb80
[FEATURE]: Create Labs Project for Ideas and Samples (#72)
github-actions[bot] Apr 17, 2025
943431c
Previous version was 'v1.1.5'. Version now 'v1.2.0'.
MattEdwardsWaggleBee Apr 17, 2025
04141d4
Simplifies expression compilation.
MattEdwardsWaggleBee May 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<!-- Solution version numbers -->
<PropertyGroup>
<MajorVersion>1</MajorVersion>
<MinorVersion>1</MinorVersion>
<PatchVersion>5</PatchVersion>
<MinorVersion>2</MinorVersion>
<PatchVersion>0</PatchVersion>
<RevisionVersion>0</RevisionVersion>
<VersionPrefix>$(MajorVersion).$(MinorVersion).$(PatchVersion)</VersionPrefix>
<FileVersion>$(MajorVersion).$(MinorVersion).$(PatchVersion).$(RevisionVersion)</FileVersion>
Expand Down
6 changes: 6 additions & 0 deletions Hyperbee.Expressions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperbee.Expressions.Tests"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hyperbee.Expressions", "src\Hyperbee.Expressions\Hyperbee.Expressions.csproj", "{FE9D5B52-7683-4B78-A7E4-2DB55EE61F22}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hyperbee.Expressions.Lab", "src\Hyperbee.Expressions.Lab\Hyperbee.Expressions.Lab.csproj", "{19728685-37C6-9A6A-128F-7D3D965E2E20}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -57,6 +59,10 @@ Global
{FE9D5B52-7683-4B78-A7E4-2DB55EE61F22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE9D5B52-7683-4B78-A7E4-2DB55EE61F22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE9D5B52-7683-4B78-A7E4-2DB55EE61F22}.Release|Any CPU.Build.0 = Release|Any CPU
{19728685-37C6-9A6A-128F-7D3D965E2E20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{19728685-37C6-9A6A-128F-7D3D965E2E20}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19728685-37C6-9A6A-128F-7D3D965E2E20}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19728685-37C6-9A6A-128F-7D3D965E2E20}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
185 changes: 185 additions & 0 deletions src/Hyperbee.Expressions.Lab/FetchExpression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
using System.Linq.Expressions;
using System.Net.Http.Headers;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;

using static Hyperbee.Expressions.ExpressionExtensions;

namespace Hyperbee.Expressions.Lab;

public class FetchExpression : Expression, IDependencyInjectionExpression
{
public Expression Url { get; }
public Expression Method { get; }
public Expression Headers { get; }
public Expression Content { get; }
public Expression ClientName { get; }

private IServiceProvider _serviceProvider;

public FetchExpression(
Expression url,
Expression method,
Expression headers = null,
Expression content = null,
Expression clientName = null )
{
ArgumentNullException.ThrowIfNull( url, nameof( url ) );
ArgumentNullException.ThrowIfNull( method, nameof( method ) );

if ( url.Type != typeof( string ) )
throw new ArgumentException( "Url must be of type string.", nameof( url ) );

if ( method.Type != typeof( HttpMethod ) )
throw new ArgumentException( "Method must be of type HttpMethod.", nameof( method ) );

if ( headers != null && headers.Type != typeof( Dictionary<string, string> ) )
throw new ArgumentException( "Headers must be of type Dictionary<string, string>.", nameof( headers ) );

Url = url;
Method = method;
Headers = headers;
Content = content;
ClientName = clientName;
}

public override Type Type => typeof( Task<HttpResponseMessage> );
public override ExpressionType NodeType => ExpressionType.Extension;
public override bool CanReduce => true;

private static readonly ConstructorInfo RequestConstructorInfo = typeof( HttpRequestMessage ).GetConstructor( [typeof( HttpMethod ), typeof( string )] );

public override Expression Reduce()
{
if ( _serviceProvider == null )
throw new InvalidOperationException( "IServiceProvider has not been set." );

// Create service provider constant
var providerConst = Constant( _serviceProvider );

Expression resolveHttpClient;

if ( ClientName != null )
{
// Resolve IHttpClientFactory and call CreateClient(name)
var getFactory = Call(
typeof( ServiceProviderServiceExtensions ),
nameof( ServiceProviderServiceExtensions.GetRequiredService ),
[typeof( IHttpClientFactory )],
providerConst
);

var factoryVar = Variable( typeof( IHttpClientFactory ), "factory" );

var assignFactory = Assign( factoryVar, getFactory );
var createClient = Call( factoryVar, nameof( IHttpClientFactory.CreateClient ), null, ClientName );

resolveHttpClient = Block(
[factoryVar],
assignFactory,
createClient
);
}
else
{
// Resolve HttpClient directly
resolveHttpClient = Call(
typeof( ServiceProviderServiceExtensions ),
nameof( ServiceProviderServiceExtensions.GetRequiredService ),
[typeof( HttpClient )],
providerConst
);
}

var clientVar = Variable( typeof( HttpClient ), "client" );
var assignClient = Assign( clientVar, resolveHttpClient );

// Create HttpRequestMessage
var requestVar = Variable( typeof( HttpRequestMessage ), "request" );

var requestCtor = New(
RequestConstructorInfo,
Method,
Url
);
var assignRequest = Assign( requestVar, requestCtor );

var variables = new List<ParameterExpression> { clientVar, requestVar };
var block = new List<Expression> {
assignClient,
assignRequest
};

// Optional headers
if ( Headers != null )
{
var headersVar = Variable( typeof( Dictionary<string, string> ), "headers" );
variables.Add( headersVar );
block.Add( Assign( headersVar, Headers ) );

var kvp = Parameter( typeof( KeyValuePair<string, string> ), "kvp" );

var addHeader = Call(
Property( requestVar, nameof( HttpRequestMessage.Headers ) ),
nameof( HttpRequestHeaders.Add ),
null,
Property( kvp, nameof( KeyValuePair<string, string>.Key ) ),
Property( kvp, nameof( KeyValuePair<string, string>.Value ) )
);

block.Add( ForEach( headersVar, kvp, addHeader ) );
}

// Optional content
if ( Content != null )
{
block.Add( Assign(
Property( requestVar, nameof( HttpRequestMessage.Content ) ),
Content
) );
}

// SendAsync call
var sendCall = Call( clientVar, nameof( HttpClient.SendAsync ), null, requestVar );

return Block(
variables,
block.Append( sendCall )
);
}

public void SetServiceProvider( IServiceProvider serviceProvider )
{
_serviceProvider = serviceProvider;
}

protected override Expression VisitChildren( ExpressionVisitor visitor )
{
return new FetchExpression(
visitor.Visit( Url ),
visitor.Visit( Method ),
Headers != null ? visitor.Visit( Headers ) : null,
Content != null ? visitor.Visit( Content ) : null,
ClientName
);
}
}

public static partial class ExpressionExtensions
{
public static FetchExpression Fetch(
Expression clientName,
Expression url )
{
return new FetchExpression( url, Expression.Constant( HttpMethod.Get ), null, null, clientName );
}

public static FetchExpression Fetch( Expression clientName,
Expression url,
Expression method,
Expression content = null,
Expression headers = null )
{
return new FetchExpression( url, method, headers, content, clientName );
}
}
84 changes: 84 additions & 0 deletions src/Hyperbee.Expressions.Lab/FetchExpressionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System.Linq.Expressions;
using System.Net.Http.Json;
using static System.Linq.Expressions.Expression;
using static Hyperbee.Expressions.ExpressionExtensions;

namespace Hyperbee.Expressions.Lab;

public static partial class ExpressionExtensions
{
public static Expression ReadJson( FetchExpression fetch, Type type )
{
return ReadJson( Await( fetch ), type );
}

public static Expression ReadJson( Expression response, Type type )
{
ArgumentNullException.ThrowIfNull( response, nameof( response ) );
ArgumentNullException.ThrowIfNull( type, nameof( type ) );

if ( response.Type != typeof( HttpResponseMessage ) )
throw new ArgumentException( "Response must be of type HttpResponseMessage.", nameof( response ) );

var readFromJsonMethodInfo = typeof( HttpContentJsonExtensions )
.GetMethod( nameof( HttpContentJsonExtensions.ReadFromJsonAsync ),
[typeof( HttpContent ), typeof( CancellationToken )] )!
.MakeGenericMethod( type );

var content = Property( response, nameof( HttpResponseMessage.Content ) );
return Call(
null,
readFromJsonMethodInfo,
content,
Default( typeof( CancellationToken ) )
);
}

public static Expression ReadText( FetchExpression fetch )
{
return ReadText( Await( fetch ) );
}

public static Expression ReadText( Expression response )
{
ArgumentNullException.ThrowIfNull( response, nameof( response ) );

return Call(
Property( response, nameof( HttpResponseMessage.Content ) ),
nameof( HttpContent.ReadAsStringAsync ),
Type.EmptyTypes
);
}

public static Expression ReadBytes( FetchExpression fetch )
{
return ReadBytes( Await( fetch ) );
}

public static Expression ReadBytes( Expression response )
{
ArgumentNullException.ThrowIfNull( response, nameof( response ) );

return Call(
Property( response, nameof( HttpResponseMessage.Content ) ),
nameof( HttpContent.ReadAsByteArrayAsync ),
Type.EmptyTypes
);
}

public static Expression ReadStream( FetchExpression fetch )
{
return ReadStream( Await( fetch ) );
}

public static Expression ReadStream( Expression response )
{
ArgumentNullException.ThrowIfNull( response, nameof( response ) );

return Call(
Property( response, nameof( HttpResponseMessage.Content ) ),
nameof( HttpContent.ReadAsStreamAsync ),
Type.EmptyTypes
);
}
}
60 changes: 60 additions & 0 deletions src/Hyperbee.Expressions.Lab/Hyperbee.Expressions.Lab.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<IsPackable>true</IsPackable>

<Authors>Stillpoint Software, Inc.</Authors>
<PackageId>Hyperbee.Expressions.Lab</PackageId>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>expression-tree;expressions;lab;samples</PackageTags>

<PackageIcon>icon.png</PackageIcon>
<PackageProjectUrl>https://stillpoint-software.github.io/hyperbee.expressions/</PackageProjectUrl>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Copyright>Stillpoint Software, Inc.</Copyright>
<Title>Hyperbee Expressions (lab)</Title>
<Description>Sample Extentions for .NET Expression Trees.</Description>
<RepositoryUrl>https://github.com/Stillpoint-Software/Hyperbee.Expressions</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageReleaseNotes>https://github.com/Stillpoint-Software/Hyperbee.Expressions/releases/latest</PackageReleaseNotes>
</PropertyGroup>

<PropertyGroup>
<DefineConstants>$(DefineConstants);FAST_COMPILER</DefineConstants>
</PropertyGroup>

<ItemGroup>
<None Update="$(MSBuildProjectName).csproj.DotSettings" Visible="false" />
</ItemGroup>

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>$(AssemblyName).Tests</_Parameter1>
</AssemblyAttribute>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>$(AssemblyName).Benchmark</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

<ItemGroup>
<None Include="..\..\assets\icon.png" Pack="true" Visible="false" PackagePath="/" />
<None Include="..\..\README.md" Pack="true" Visible="true" PackagePath="/" Link="README.md" />
<None Include="..\..\LICENSE" Pack="true" Visible="false" PackagePath="/" />
<PackageReference Include="Hyperbee.Collections" Version="2.4.0" />
<PackageReference Include="Hyperbee.Json" Version="3.0.3" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.4" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.4" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.4" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.4" />
<ProjectReference Include="..\Hyperbee.Expressions\Hyperbee.Expressions.csproj" />
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
Loading
Loading