Category: .NET 7

RSCG – Vogen

RSCG – Vogen
 
 

name Vogen
nuget https://www.nuget.org/packages/Vogen/
link https://dunnhq.com/posts/2021/primitive-obsession/
author Steve Dunn

Transform values( e.g. int) into classes

If you know what are ValueObject,that is one solution

 

This is how you can use Vogen .

The code that you start with is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
 
  <ItemGroup>
    <PackageReference Include="Vogen" Version="3.0.16" />
  </ItemGroup>
<PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
</Project>

The code that you will use is

01
02
03
04
05
06
07
08
09
10
11
12
// See https://aka.ms/new-console-template for more information
 
using DemoVogen;
 
Console.WriteLine("Hello, World!");
var p = PersonId.From(123);
var p1 = PersonId.From(123);
var p2 =(PersonId) 123;
 
Console.WriteLine(p == 123);
Console.WriteLine(p == p1);
Console.WriteLine(p == p2);
1
2
3
4
5
6
7
// See https://aka.ms/new-console-template for more information
using Vogen;
namespace DemoVogen;
[ValueObject<int>]
public partial struct PersonId
{
}

 

The code that is generated is

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
// ------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a source generator named Vogen (https://github.com/SteveDunn/Vogen)
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
 
// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
 
// Suppress warnings for 'Override methods on comparable types'.
#pragma warning disable CA1036
 
// Suppress Error MA0097 : A class that implements IComparable<T> or IComparable should override comparison operators
#pragma warning disable MA0097
 
// Suppress warning for 'The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.'
// The generator copies signatures from the BCL, e.g. for `TryParse`, and some of those have nullable annotations.
#pragma warning disable CS8669
 
// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member'
#pragma warning disable CS1591
 
using Vogen;
 
namespace DemoVogen
{
 
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "3.0.0.0")]
    [global::System.Text.Json.Serialization.JsonConverter(typeof(PersonIdSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(PersonIdTypeConverter))]
 
    [global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(PersonIdDebugView))]
    [global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.Int32, Value = { _value }")]
    public partial struct PersonId : global::System.IEquatable<PersonId>, global::System.IEquatable<System.Int32> ,  global::System.IComparable<PersonId>, global::System.IComparable
    {
#if DEBUG   
        private readonly global::System.Diagnostics.StackTrace _stackTrace = null;
#endif
 
        private readonly global::System.Boolean _isInitialized;
         
        private readonly System.Int32 _value;
 
        /// <summary>
        /// Gets the underlying <see cref="System.Int32" /> value if set, otherwise a <see cref="ValueObjectValidationException" /> is thrown.
        /// </summary>
        public readonly System.Int32 Value
        {
            [global::System.Diagnostics.DebuggerStepThroughAttribute]
            get
            {
                EnsureInitialized();
                return _value;
            }
        }
 
        [global::System.Diagnostics.DebuggerStepThroughAttribute]
        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
        public PersonId()
        {
#if DEBUG
            _stackTrace = new global::System.Diagnostics.StackTrace();
#endif
 
            _isInitialized = false;
            _value = default;
        }
 
        [global::System.Diagnostics.DebuggerStepThroughAttribute]
        private PersonId(System.Int32 value)
        {
            _value = value;
            _isInitialized = true;
        }
 
        /// <summary>
        /// Builds an instance from the provided underlying type.
        /// </summary>
        /// <param name="value">The underlying type.</param>
        /// <returns>An instance of this type.</returns>
        public static PersonId From(System.Int32 value)
        {
             
 
            PersonId instance = new PersonId(value);
 
             
 
            return instance;
        }
 
        public static explicit operator PersonId(System.Int32 value) => From(value);
        public static explicit operator System.Int32(PersonId value) => value.Value;
 
        // only called internally when something has been deserialized into
        // its primitive type.
        private static PersonId Deserialize(System.Int32 value)
        {
             
 
             
 
            return new PersonId(value);
        }
 
        public readonly global::System.Boolean Equals(PersonId other)
        {
            // It's possible to create uninitialized instances via converters such as EfCore (HasDefaultValue), which call Equals.
            // We treat anything uninitialized as not equal to anything, even other uninitialized instances of this type.
            if(!_isInitialized || !other._isInitialized) return false;
 
            return global::System.Collections.Generic.EqualityComparer<System.Int32>.Default.Equals(Value, other.Value);
        }
 
        public readonly global::System.Boolean Equals(System.Int32 primitive) => Value.Equals(primitive);
 
        public readonly override global::System.Boolean Equals(global::System.Object obj)
        {
            return obj is PersonId && Equals((PersonId) obj);
        }
 
        public static global::System.Boolean operator ==(PersonId left, PersonId right) => Equals(left, right);
        public static global::System.Boolean operator !=(PersonId left, PersonId right) => !(left == right);
 
        public static global::System.Boolean operator ==(PersonId left, System.Int32 right) => Equals(left.Value, right);
        public static global::System.Boolean operator !=(PersonId left, System.Int32 right) => !Equals(left.Value, right);
 
        public static global::System.Boolean operator ==(System.Int32 left, PersonId right) => Equals(left, right.Value);
        public static global::System.Boolean operator !=(System.Int32 left, PersonId right) => !Equals(left, right.Value);
 
        public int CompareTo(PersonId other) => Value.CompareTo(other.Value);
        public int CompareTo(object other) {
            if(other == null) return 1;
            if(other is PersonId x) return CompareTo(x);
            throw new global::System.ArgumentException("Cannot compare to object as it is not of type PersonId", nameof(other));
        }
 
         
    /// <inheritdoc cref="int.TryParse(System.ReadOnlySpan{char}, System.Globalization.NumberStyles, System.IFormatProvider?, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, style, provider, out var r)) {
            result = From(r);
            return true;
        }
 
        result = default;
        return false;
    }
 
    /// <inheritdoc cref="int.TryParse(System.ReadOnlySpan{char}, System.IFormatProvider?, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> s, global::System.IFormatProvider provider,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, provider, out var r)) {
            result = From(r);
            return true;
        }
 
        result = default;
        return false;
    }
 
    /// <inheritdoc cref="int.TryParse(System.ReadOnlySpan{char}, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> s,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, out var r)) {
            result = From(r);
            return true;
        }
 
        result = default;
        return false;
    }
 
    /// <inheritdoc cref="int.TryParse(string?, System.Globalization.NumberStyles, System.IFormatProvider?, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(string s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, style, provider, out var r)) {
            result = From(r);
            return true;
        }
 
        result = default;
        return false;
    }
 
    /// <inheritdoc cref="int.TryParse(string?, System.IFormatProvider?, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(string s, global::System.IFormatProvider provider,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, provider, out var r)) {
            result = From(r);
            return true;
        }
 
        result = default;
        return false;
    }
 
    /// <inheritdoc cref="int.TryParse(string?, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(string s,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, out var r)) {
            result = From(r);
            return true;
        }
 
        result = default;
        return false;
    }
 
 
        public readonly override global::System.Int32 GetHashCode() => global::System.Collections.Generic.EqualityComparer<System.Int32>.Default.GetHashCode(_value);
 
        /// <summary>Returns the string representation of the underlying type</summary>
    /// <inheritdoc cref="System.Int32.ToString()" />
    public readonly override global::System.String ToString() =>_isInitialized ? Value.ToString() : "[UNINITIALIZED]";
 
        private readonly void EnsureInitialized()
        {
            if (!_isInitialized)
            {
#if DEBUG
                global::System.String message = "Use of uninitialized Value Object at: " + _stackTrace ?? "";
#else
                global::System.String message = "Use of uninitialized Value Object.";
#endif
 
                throw new global::Vogen.ValueObjectValidationException(message);
            }
        }
 
         
  
         
        class PersonIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter<PersonId>
        {
            public override PersonId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
            {
                return PersonId.Deserialize(reader.GetInt32());
            }
 
            public override void Write(System.Text.Json.Utf8JsonWriter writer, PersonId value, global::System.Text.Json.JsonSerializerOptions options)
            {
                writer.WriteNumberValue(value.Value);
            }
 
#if NET6_0_OR_GREATER           
            public override PersonId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
            {
                return PersonId.Deserialize(global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture));
            }
 
            public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, PersonId value, global::System.Text.Json.JsonSerializerOptions options)
            {
                writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture));
            }
#endif
        }
 
 
        class PersonIdTypeConverter : global::System.ComponentModel.TypeConverter
        {
            public override global::System.Boolean CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
            {
                return sourceType == typeof(global::System.Int32) || sourceType == typeof(global::System.String) || base.CanConvertFrom(context, sourceType);
            }
 
            public override global::System.Object ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value)
            {
                return value switch
                {
                    global::System.Int32 intValue => PersonId.Deserialize(intValue),
                    global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Int32.TryParse(stringValue, out var result) => PersonId.Deserialize(result),
                    _ => base.ConvertFrom(context, culture, value),
                };
            }
 
            public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
            {
                return sourceType == typeof(global::System.Int32) || sourceType == typeof(global::System.String) || base.CanConvertTo(context, sourceType);
            }
 
            public override object ConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value, global::System.Type destinationType)
            {
                if (value is PersonId idValue)
                {
                    if (destinationType == typeof(global::System.Int32))
                    {
                        return idValue.Value;
                    }
 
                    if (destinationType == typeof(global::System.String))
                    {
                        return idValue.Value.ToString();
                    }
                }
 
                return base.ConvertTo(context, culture, value, destinationType);
            }
        }
 
 
 
 
 
        internal sealed class PersonIdDebugView
        {
            private readonly PersonId _t;
 
            PersonIdDebugView(PersonId t)
            {
                _t = t;
            }
 
            public global::System.Boolean IsInitialized => _t._isInitialized;
            public global::System.String UnderlyingType => "System.Int32";
            public global::System.String Value => _t._isInitialized ? _t._value.ToString() : "[not initialized]" ;
 
            #if DEBUG
            public global::System.String CreatedWith => _t._stackTrace?.ToString() ?? "the From method";
            #endif
 
            public global::System.String Conversions => @"Default";
                }
 
}
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Vogen

RSCG – dunet

RSCG – dunet
 
 

name dunet
nuget https://www.nuget.org/packages/dunet/
link https://github.com/domn1995/dunet
author Domn Werner

Add union types to C# – similar with F#/TS discriminated unions

Check his examples- awesome

 

This is how you can use dunet .

The code that you start with is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
<Project Sdk="Microsoft.NET.Sdk">
 
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>
 
    <ItemGroup>
        <PackageReference Include="Dunet" Version="1.8.0">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
        </PackageReference>
    </ItemGroup>
    <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
 
</Project>

The code that you will use is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// See https://github.com/domn1995/dunet for more examples
using duneDemo;
Console.WriteLine(WhatIsTheString.FromString("1"));
 
Console.WriteLine(WhatIsTheString.FromString("Andrei"));
 
Console.WriteLine(WhatIsTheString.FromString("1970-04-16"));
 
Console.WriteLine("Enter something - 1, 1970-04-16 or Andrei !");
var readLine = Console.ReadLine();
var opt= WhatIsTheString.FromString(readLine);
Console.WriteLine(opt);
//if if it long
opt.MatchIsLong(
    l => Console.WriteLine("is long " + l.value),
    () => Console.WriteLine("is not long")
    ) ;
//C# switch
var x=opt switch
{
    WhatIsTheString.IsLong l => "is long " +l.value,
    WhatIsTheString.IsDate d=> "is date "+ d.value,
    WhatIsTheString.IsString s=>"is string "+ s.value,
    WhatIsTheString.IsNullWhiteSpace w=>"no data",
    _ => throw new NotImplementedException()
 
};
Console.WriteLine(x);
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using Dunet;
namespace duneDemo;
 
[Union]
partial record WhatIsTheString
{
    partial record IsString(string value);
    partial record IsLong(long value);
    partial record IsDate(DateTime value);
 
    partial record IsNullWhiteSpace();
 
    public static WhatIsTheString FromString(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
            return new IsNullWhiteSpace();
 
        if(long.TryParse(value, out var longValue))
        {
            return new IsLong(longValue);
        }
        if(DateTime.TryParse(value, out var dateTimeValue))
        {
            return new IsDate(dateTimeValue);
        }
        return new IsString(value);
    }
 
}

 

The code that is generated is

1
2
3
4
5
6
7
8
9
using System;
 
namespace Dunet;
 
/// <summary>
/// Enables dunet union source generation for the decorated partial record.
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
internal sealed class UnionAttribute : Attribute {}
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
#pragma warning disable 1591
namespace duneDemo;
abstract partial record WhatIsTheString
{
    private WhatIsTheString() {}
 
    public abstract TMatchOutput Match<TMatchOutput>(
        System.Func<IsString, TMatchOutput> @isString,
        System.Func<IsLong, TMatchOutput> @isLong,
        System.Func<IsDate, TMatchOutput> @isDate,
        System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
    );
    public abstract void Match(
        System.Action<IsString> @isString,
        System.Action<IsLong> @isLong,
        System.Action<IsDate> @isDate,
        System.Action<IsNullWhiteSpace> @isNullWhiteSpace
    );
 
    public abstract TMatchOutput Match<TState, TMatchOutput>(
        TState state,
        System.Func<TState, IsString, TMatchOutput> @isString,
        System.Func<TState, IsLong, TMatchOutput> @isLong,
        System.Func<TState, IsDate, TMatchOutput> @isDate,
        System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
    );
    public abstract void Match<TState>(
        TState state,
        System.Action<TState, IsString> @isString,
        System.Action<TState, IsLong> @isLong,
        System.Action<TState, IsDate> @isDate,
        System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace
    );
 
    public abstract TMatchOutput MatchIsString<TMatchOutput>(
        System.Func<IsString, TMatchOutput> @isString,
        System.Func<TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsLong<TMatchOutput>(
        System.Func<IsLong, TMatchOutput> @isLong,
        System.Func<TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsDate<TMatchOutput>(
        System.Func<IsDate, TMatchOutput> @isDate,
        System.Func<TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsNullWhiteSpace<TMatchOutput>(
        System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
        System.Func<TMatchOutput> @else
    );
 
    public abstract void MatchIsString(
        System.Action<IsString> @isString,
        System.Action @else
    );
    public abstract void MatchIsLong(
        System.Action<IsLong> @isLong,
        System.Action @else
    );
    public abstract void MatchIsDate(
        System.Action<IsDate> @isDate,
        System.Action @else
    );
    public abstract void MatchIsNullWhiteSpace(
        System.Action<IsNullWhiteSpace> @isNullWhiteSpace,
        System.Action @else
    );
 
    public abstract TMatchOutput MatchIsString<TState, TMatchOutput>(
        TState state,
        System.Func<TState, IsString, TMatchOutput> @isString,
        System.Func<TState, TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsLong<TState, TMatchOutput>(
        TState state,
        System.Func<TState, IsLong, TMatchOutput> @isLong,
        System.Func<TState, TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsDate<TState, TMatchOutput>(
        TState state,
        System.Func<TState, IsDate, TMatchOutput> @isDate,
        System.Func<TState, TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsNullWhiteSpace<TState, TMatchOutput>(
        TState state,
        System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
        System.Func<TState, TMatchOutput> @else
    );
 
    public abstract void MatchIsString<TState>(
        TState state,
        System.Action<TState, IsString> @isString,
        System.Action<TState> @else
    );
    public abstract void MatchIsLong<TState>(
        TState state,
        System.Action<TState, IsLong> @isLong,
        System.Action<TState> @else
    );
    public abstract void MatchIsDate<TState>(
        TState state,
        System.Action<TState, IsDate> @isDate,
        System.Action<TState> @else
    );
    public abstract void MatchIsNullWhiteSpace<TState>(
        TState state,
        System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace,
        System.Action<TState> @else
    );
 
    public sealed partial record IsString : WhatIsTheString
    {
        public override TMatchOutput Match<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isString(this);
        public override void Match(
            System.Action<IsString> @isString,
            System.Action<IsLong> @isLong,
            System.Action<IsDate> @isDate,
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isString(this);
        public override TMatchOutput Match<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isString(state, this);
        public override void Match<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isString(state, this);
        public override TMatchOutput MatchIsString<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<TMatchOutput> @else
        ) => @isString(this);
        public override TMatchOutput MatchIsLong<TMatchOutput>(
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsDate<TMatchOutput>(
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsNullWhiteSpace<TMatchOutput>(
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override void MatchIsString(
            System.Action<IsString> @isString,
            System.Action @else
        ) => @isString(this);
        public override void MatchIsLong(
            System.Action<IsLong> @isLong,
            System.Action @else
        ) => @else();
        public override void MatchIsDate(
            System.Action<IsDate> @isDate,
            System.Action @else
        ) => @else();
        public override void MatchIsNullWhiteSpace(
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action @else
        ) => @else();
        public override TMatchOutput MatchIsString<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, TMatchOutput> @else
        ) => @isString(state, this);
        public override TMatchOutput MatchIsLong<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsDate<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsNullWhiteSpace<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override void MatchIsString<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState> @else
        ) => @isString(state, this);
        public override void MatchIsLong<TState>(
        TState state,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsDate<TState>(
        TState state,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsNullWhiteSpace<TState>(
        TState state,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action<TState> @else
        ) => @else(state);
    }
 
    public sealed partial record IsLong : WhatIsTheString
    {
        public override TMatchOutput Match<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isLong(this);
        public override void Match(
            System.Action<IsString> @isString,
            System.Action<IsLong> @isLong,
            System.Action<IsDate> @isDate,
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isLong(this);
        public override TMatchOutput Match<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isLong(state, this);
        public override void Match<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isLong(state, this);
        public override TMatchOutput MatchIsString<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsLong<TMatchOutput>(
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<TMatchOutput> @else
        ) => @isLong(this);
        public override TMatchOutput MatchIsDate<TMatchOutput>(
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsNullWhiteSpace<TMatchOutput>(
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override void MatchIsString(
            System.Action<IsString> @isString,
            System.Action @else
        ) => @else();
        public override void MatchIsLong(
            System.Action<IsLong> @isLong,
            System.Action @else
        ) => @isLong(this);
        public override void MatchIsDate(
            System.Action<IsDate> @isDate,
            System.Action @else
        ) => @else();
        public override void MatchIsNullWhiteSpace(
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action @else
        ) => @else();
        public override TMatchOutput MatchIsString<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsLong<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, TMatchOutput> @else
        ) => @isLong(state, this);
        public override TMatchOutput MatchIsDate<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsNullWhiteSpace<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override void MatchIsString<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsLong<TState>(
        TState state,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState> @else
        ) => @isLong(state, this);
        public override void MatchIsDate<TState>(
        TState state,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsNullWhiteSpace<TState>(
        TState state,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action<TState> @else
        ) => @else(state);
    }
 
    public sealed partial record IsDate : WhatIsTheString
    {
        public override TMatchOutput Match<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isDate(this);
        public override void Match(
            System.Action<IsString> @isString,
            System.Action<IsLong> @isLong,
            System.Action<IsDate> @isDate,
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isDate(this);
        public override TMatchOutput Match<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isDate(state, this);
        public override void Match<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isDate(state, this);
        public override TMatchOutput MatchIsString<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsLong<TMatchOutput>(
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsDate<TMatchOutput>(
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<TMatchOutput> @else
        ) => @isDate(this);
        public override TMatchOutput MatchIsNullWhiteSpace<TMatchOutput>(
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override void MatchIsString(
            System.Action<IsString> @isString,
            System.Action @else
        ) => @else();
        public override void MatchIsLong(
            System.Action<IsLong> @isLong,
            System.Action @else
        ) => @else();
        public override void MatchIsDate(
            System.Action<IsDate> @isDate,
            System.Action @else
        ) => @isDate(this);
        public override void MatchIsNullWhiteSpace(
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action @else
        ) => @else();
        public override TMatchOutput MatchIsString<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsLong<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsDate<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, TMatchOutput> @else
        ) => @isDate(state, this);
        public override TMatchOutput MatchIsNullWhiteSpace<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override void MatchIsString<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsLong<TState>(
        TState state,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsDate<TState>(
        TState state,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState> @else
        ) => @isDate(state, this);
        public override void MatchIsNullWhiteSpace<TState>(
        TState state,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action<TState> @else
        ) => @else(state);
    }
 
    public sealed partial record IsNullWhiteSpace : WhatIsTheString
    {
        public override TMatchOutput Match<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isNullWhiteSpace(this);
        public override void Match(
            System.Action<IsString> @isString,
            System.Action<IsLong> @isLong,
            System.Action<IsDate> @isDate,
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isNullWhiteSpace(this);
        public override TMatchOutput Match<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isNullWhiteSpace(state, this);
        public override void Match<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isNullWhiteSpace(state, this);
        public override TMatchOutput MatchIsString<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsLong<TMatchOutput>(
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsDate<TMatchOutput>(
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsNullWhiteSpace<TMatchOutput>(
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TMatchOutput> @else
        ) => @isNullWhiteSpace(this);
        public override void MatchIsString(
            System.Action<IsString> @isString,
            System.Action @else
        ) => @else();
        public override void MatchIsLong(
            System.Action<IsLong> @isLong,
            System.Action @else
        ) => @else();
        public override void MatchIsDate(
            System.Action<IsDate> @isDate,
            System.Action @else
        ) => @else();
        public override void MatchIsNullWhiteSpace(
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action @else
        ) => @isNullWhiteSpace(this);
        public override TMatchOutput MatchIsString<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsLong<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsDate<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsNullWhiteSpace<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TState, TMatchOutput> @else
        ) => @isNullWhiteSpace(state, this);
        public override void MatchIsString<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsLong<TState>(
        TState state,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsDate<TState>(
        TState state,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsNullWhiteSpace<TState>(
        TState state,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action<TState> @else
        ) => @isNullWhiteSpace(state, this);
    }
 
}
#pragma warning restore 1591
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#pragma warning disable 1591
 
namespace duneDemo;
 
internal static class WhatIsTheStringMatchExtensions
{
    public static async System.Threading.Tasks.Task<TMatchOutput> MatchAsync<TMatchOutput>(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsString, TMatchOutput> @isString,
        System.Func<WhatIsTheString.IsLong, TMatchOutput> @isLong,
        System.Func<WhatIsTheString.IsDate, TMatchOutput> @isDate,
        System.Func<WhatIsTheString.IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
    )
    => (await unionTask.ConfigureAwait(false)).Match(
            @isString,
            @isLong,
            @isDate,
            @isNullWhiteSpace
        );
    public static async System.Threading.Tasks.ValueTask<TMatchOutput> MatchAsync<TMatchOutput>(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsString, TMatchOutput> @isString,
        System.Func<WhatIsTheString.IsLong, TMatchOutput> @isLong,
        System.Func<WhatIsTheString.IsDate, TMatchOutput> @isDate,
        System.Func<WhatIsTheString.IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
    )
    => (await unionTask.ConfigureAwait(false)).Match(
            @isString,
            @isLong,
            @isDate,
            @isNullWhiteSpace
        );
    public static async System.Threading.Tasks.Task MatchAsync(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsString> @isString,
        System.Action<WhatIsTheString.IsLong> @isLong,
        System.Action<WhatIsTheString.IsDate> @isDate,
        System.Action<WhatIsTheString.IsNullWhiteSpace> @isNullWhiteSpace
    )
    => (await unionTask.ConfigureAwait(false)).Match(
            @isString,
            @isLong,
            @isDate,
            @isNullWhiteSpace
        );
    public static async System.Threading.Tasks.ValueTask MatchAsync(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsString> @isString,
        System.Action<WhatIsTheString.IsLong> @isLong,
        System.Action<WhatIsTheString.IsDate> @isDate,
        System.Action<WhatIsTheString.IsNullWhiteSpace> @isNullWhiteSpace
    )
    => (await unionTask.ConfigureAwait(false)).Match(
            @isString,
            @isLong,
            @isDate,
            @isNullWhiteSpace
        );
    public static async System.Threading.Tasks.Task<TMatchOutput> MatchIsStringAsync<TMatchOutput>(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsString, TMatchOutput> @isString,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsString(
                    @isString,
                    @else
                );
    public static async System.Threading.Tasks.Task<TMatchOutput> MatchIsLongAsync<TMatchOutput>(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsLong, TMatchOutput> @isLong,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsLong(
                    @isLong,
                    @else
                );
    public static async System.Threading.Tasks.Task<TMatchOutput> MatchIsDateAsync<TMatchOutput>(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsDate, TMatchOutput> @isDate,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsDate(
                    @isDate,
                    @else
                );
    public static async System.Threading.Tasks.Task<TMatchOutput> MatchIsNullWhiteSpaceAsync<TMatchOutput>(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsNullWhiteSpace(
                    @isNullWhiteSpace,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask<TMatchOutput> MatchIsStringAsync<TMatchOutput>(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsString, TMatchOutput> @isString,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsString(
                    @isString,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask<TMatchOutput> MatchIsLongAsync<TMatchOutput>(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsLong, TMatchOutput> @isLong,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsLong(
                    @isLong,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask<TMatchOutput> MatchIsDateAsync<TMatchOutput>(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsDate, TMatchOutput> @isDate,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsDate(
                    @isDate,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask<TMatchOutput> MatchIsNullWhiteSpaceAsync<TMatchOutput>(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsNullWhiteSpace(
                    @isNullWhiteSpace,
                    @else
                );
    public static async System.Threading.Tasks.Task MatchIsStringAsync(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsString> @isString,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsString(
                    @isString,
                    @else
                );
    public static async System.Threading.Tasks.Task MatchIsLongAsync(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsLong> @isLong,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsLong(
                    @isLong,
                    @else
                );
    public static async System.Threading.Tasks.Task MatchIsDateAsync(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsDate> @isDate,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsDate(
                    @isDate,
                    @else
                );
    public static async System.Threading.Tasks.Task MatchIsNullWhiteSpaceAsync(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsNullWhiteSpace> @isNullWhiteSpace,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsNullWhiteSpace(
                    @isNullWhiteSpace,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask MatchIsStringAsync(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsString> @isString,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsString(
                    @isString,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask MatchIsLongAsync(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsLong> @isLong,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsLong(
                    @isLong,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask MatchIsDateAsync(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsDate> @isDate,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsDate(
                    @isDate,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask MatchIsNullWhiteSpaceAsync(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsNullWhiteSpace> @isNullWhiteSpace,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsNullWhiteSpace(
                    @isNullWhiteSpace,
                    @else
                );
}
#pragma warning restore 1591

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/dunet

RSCG – AutoCtor

RSCG – AutoCtor
 
 

name AutoCtor
nuget https://www.nuget.org/packages/AutoCtor/
link
author Cameron MacFarland

Generate constructor from non-initialized fields

 

This is how you can use AutoCtor .

The code that you start with is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
    <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="AutoCtor" Version="1.0.0" />
    </ItemGroup>
</Project>

The code that you will use is

1
2
3
4
5
6
// See https://aka.ms/new-console-template for more information
using AutoCtorDemo;
 
Console.WriteLine("Hello, World!");
 
var p = new Person("Andrei", "Ignat");
01
02
03
04
05
06
07
08
09
10
11
using AutoCtor;
 
namespace AutoCtorDemo;
 
[AutoConstruct]
internal partial class Person
{
    private readonly string FirstName;
    private readonly string? LastName;
 
}

 

The code that is generated is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
 
#if AUTOCTOR_EMBED_ATTRIBUTES
namespace AutoCtor
{
    [System.Runtime.CompilerServices.CompilerGenerated]
    [System.AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
    [System.Diagnostics.Conditional("AUTOCTOR_USAGES")]
    internal sealed class AutoConstructAttribute : System.Attribute
    {
        [System.Runtime.CompilerServices.CompilerGenerated]
        public AutoConstructAttribute()
        {
        }
    }
}
#endif
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
 
namespace AutoCtorDemo
{
    partial class Person
    {
        public Person(string FirstName, string LastName)
        {
            this.FirstName = FirstName;
            this.LastName = LastName;
        }
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/AutoCtor

RSCG – QuickConstructor

RSCG – QuickConstructor
 
 

name QuickConstructor
nuget https://www.nuget.org/packages/QuickConstructor
link https://github.com/flavien/QuickConstructor
author Flavien Charlon

Fast add constructors that are read only FIELDS

Has multiple other features

 

This is how you can use QuickConstructor .

The code that you start with is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
 
  <ItemGroup>
    <PackageReference Include="QuickConstructor" Version="1.0.5" />
  </ItemGroup>
    <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
</Project>

The code that you will use is

1
2
3
using QuickConstructorDemo;
 
var p = new Person("Andrei", "Ignat");
01
02
03
04
05
06
07
08
09
10
11
12
using QuickConstructor.Attributes;
 
namespace QuickConstructorDemo;
 
[QuickConstructor]
internal partial class Person
{
    private readonly string FirstName;
    private readonly string? LastName;
 
     
}

 

The code that is generated is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <auto-generated>
/// This code was generated by the QuickConstructor source generator.
/// </auto-generated>
 
#nullable enable
 
namespace QuickConstructorDemo
{
    partial class Person
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Person" /> class.
        /// </summary>
        public Person(string @firstName, string? @lastName)
        {
            if (@firstName == null)
                throw new global::System.ArgumentNullException(nameof(@firstName));
 
            this.@FirstName = @firstName;
            this.@LastName = @lastName;
        }
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/QuickConstructor

RSCG – System.Runtime.InteropServices

RSCG – System.Runtime.InteropServices
 
 

name System.Runtime.InteropServices
nuget https://www.nuget.org/packages/System.Runtime.InteropServices/
link https://learn.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke-source-generation
author Microsoft

Generate PInvoke calls

 

This is how you can use System.Runtime.InteropServices .

The code that you start with is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
    <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    </PropertyGroup>
</Project>

The code that you will use is

1
2
3
WriteLine(MessageBoxW(IntPtr.Zero, "asd", "asd", 1));
//RSCG
WriteLine(MessageBoxW_LI(IntPtr.Zero, "asd", "asd", 1));
01
02
03
04
05
06
07
08
09
10
11
12
partial class DemoImport
{
    [DllImport("user32.dll", EntryPoint = "MessageBoxW", CharSet = CharSet.Unicode, SetLastError = true)]
 
    internal static extern int MessageBoxW(IntPtr hWnd, string lpText, string lpCaption, uint uType);
 
 
    [LibraryImport("user32.dll", EntryPoint = "MessageBoxW", SetLastError = true,
StringMarshalling = StringMarshalling.Utf16)]
 
    internal static partial int MessageBoxW_LI(IntPtr hWnd, string lpText, string lpCaption, uint uType);
}
1
2
3
global using static System.Console;
global using static DemoImport;
global using System.Runtime.InteropServices;

 

The code that is generated is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// <auto-generated/>
unsafe partial class DemoImport
{
    [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Interop.LibraryImportGenerator", "7.0.8.17405")]
    [System.Runtime.CompilerServices.SkipLocalsInitAttribute]
    internal static partial int MessageBoxW_LI(nint hWnd, string lpText, string lpCaption, uint uType)
    {
        int __lastError;
        int __retVal;
        // Pin - Pin data in preparation for calling the P/Invoke.
        fixed (void* __lpText_native = &global::System.Runtime.InteropServices.Marshalling.Utf16StringMarshaller.GetPinnableReference(lpText))
        fixed (void* __lpCaption_native = &global::System.Runtime.InteropServices.Marshalling.Utf16StringMarshaller.GetPinnableReference(lpCaption))
        {
            System.Runtime.InteropServices.Marshal.SetLastSystemError(0);
            __retVal = __PInvoke(hWnd, (ushort*)__lpText_native, (ushort*)__lpCaption_native, uType);
            __lastError = System.Runtime.InteropServices.Marshal.GetLastSystemError();
        }
 
        System.Runtime.InteropServices.Marshal.SetLastPInvokeError(__lastError);
        return __retVal;
        // Local P/Invoke
        [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "MessageBoxW", ExactSpelling = true)]
        static extern unsafe int __PInvoke(nint hWnd, ushort* lpText, ushort* lpCaption, uint uType);
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/System.Runtime.InteropServices

Db2Code–part 2- architecture

What we will build you can see here :

Each class will have it is own CodeTemplates\EFCore  templates from which will generate the code.

Let’s start with ExampleModels : Here will be the class definitions . From the table defintion , the DB2Code will generate

1. A definition of a interface with table columns as properties

1
2
3
4
5
public interface I_Department_Table
{
 long IDDepartment { get; set; }
 string Name { get; set; }
}

2. A class with relationships

01
02
03
04
05
06
07
08
09
10
11
12
public partial class Department
{
    [Key]
    public long IDDepartment { get; set; }
 
    [StringLength(50)]
    [Unicode(false)]
    public string Name { get; set; } = null!;
 
    [InverseProperty("IDDepartmentNavigation")]
    public virtual ICollection&lt;Employee&gt; Employee { get; } = new List&lt;Employee&gt;();
}

3. class without relationship

1
2
3
4
5
public class Department_Table : I_Department_Table
{
 public long IDDepartment { get; set; }
 public string Name { get; set; }
 }

4. Explicit operator to convert 2 to 3

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
public static explicit operator Department_Table?(Department obj) {
if(obj == null)
return null;
//System.Diagnostics.Debugger.Break();
var ret= new Department_Table();
ret.CopyFrom(obj as I_Department_Table );
return ret;
}
public static explicit operator Department?(Department_Table obj) {
if(obj == null)
return null;
//System.Diagnostics.Debugger.Break();
var ret= new Department();
ret.CopyFrom(obj as I_Department_Table) ;
return ret;
}

5. Public method CopyFrom( interface)

1
2
3
4
public void CopyFrom(I_Department_Table other)  {
 this.IDDepartment = other.IDDepartment;
 this.Name = other.Name;
}

5. Enum with name of the columns

1
2
3
4
5
public enum eDepartmentColumns {
None = 0
,IDDepartment
,Name
}

6. Metadata with name of the tables and the columns

1
2
3
4
5
6
7
8
public static MetaTable metaData = new("Department");
static Department_Table (){
 MetaColumn mc=null;
 mc=new ("IDDepartment","long",false);
 metaData.AddColumn(mc);
 mc=new ("Name","string",false);
 metaData.AddColumn(mc);
}

 

Now it comes ExampleContext . Here will the database context and various search definitions that you need (e.g. for a column of type int, search will generate  = , > , < , between , in array  ) . More , it will generate metadata for the tables that are part of the context.

1
2
3
4
public  IAsyncEnumerable&lt;Department&gt; DepartmentSimpleSearch(GeneratorFromDB.SearchCriteria sc, eDepartmentColumns colToSearch, string value){}
public  IAsyncEnumerable&lt;Department&gt; DepartmentGetAll(){}
public async Task&lt;Department[]&gt; DepartmentFind_Array( SearchDepartment? search){}
public Task&lt;long&gt; DepartmentCount( SearchDepartment search)

 

Now it comes ExampleControllers  . This will generate controllers for REST API for the table and also Search Controllers for any kind of search that you may want.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
//this is the REST controller
[ApiController]
[Route("[controller]")]   
public partial class RESTDepartmentController : Controller
{
    private ApplicationDBContext _context;
    public RESTDepartmentController(ApplicationDBContext context)
    {
        _context=context;
    }
    [HttpGet]
    public async Task&lt;Department_Table[]&gt; Get(){
        var data= await _context.Department.ToArrayAsync();
        var ret = data.Select(it =&gt; (Department_Table)it!).ToArray();
        return ret;
 
         
    }
     
        [HttpGet("{id}")]
    public async Task&lt;ActionResult&lt;Department_Table&gt;&gt; GetDepartment(long id)
    {
        if (_context.Department == null)
        {
            return NotFound();
        }
        var item = await _context.Department.FirstOrDefaultAsync(e =&gt; e.IDDepartment==id);
 
        if (item == null)
        {
            return NotFound();
        }
 
        return (Department_Table)item!;
    }
 
 
    [HttpPatch("{id}")]
        public async Task&lt;IActionResult&gt; PutDepartment(long id, Department value)
        {
            if (id != value.IDDepartment)
            {
                return BadRequest();
            }
 
            _context.Entry(value).State = EntityState.Modified;
 
            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!DepartmentExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
 
            return NoContent();
        }
 
        [HttpPost]
        public async Task&lt;ActionResult&lt;Department&gt;&gt; PostDepartment(Department_Table value)
        {
           
            var val = new Department();
            val.CopyFrom(value);
            _context.Department.Add(val);
            await _context.SaveChangesAsync();
 
            return CreatedAtAction("GetDepartment", new { id = val.IDDepartment }, val);
        }
        [HttpDelete("{id}")]
        public async Task&lt;IActionResult&gt; DeleteDepartment(long id)
        {
            if (_context.Department == null)
            {
                return NotFound();
            }
            var item = await _context.Department.FirstOrDefaultAsync(e =&gt; e.IDDepartment==id);
            if (item == null)
            {
                return NotFound();
            }
 
            _context.Department .Remove(item);
            await _context.SaveChangesAsync();
 
            return NoContent();
        }
 
        private bool DepartmentExists(long id)
        {
            return (_context.Department.Any(e =&gt; e.IDDepartment  == id));
        }
 
    }   

And also a SEARCH controller

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
[ApiController]
[Route("[controller]/[action]")]   
public partial class AdvancedSearchDepartmentController : Controller
{
    private ISearchDataDepartment _search;
    public AdvancedSearchDepartmentController(ISearchDataDepartment search)
    {
        _search=search;
    }
 
    [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; GetAll()
    {
        await foreach(var item in _search.DepartmentFind_AsyncEnumerable(null))
        {
            yield return (Department_Table)item!;
        }
         
    }
    [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; GetWithSearch(SearchDepartment s)
    {
        await foreach(var item in _search.DepartmentFind_AsyncEnumerable(s))
        {
            yield return (Department_Table)item!;
        }
         
    }
 
//has one key
    [HttpGet]
    public async Task&lt;Department_Table?&gt; GetSingle(long id){
        var data=await _search.DepartmentGetSingle(id);
       if(data == null)
        return null;
       return (Department_Table)data;
    }
 
                  [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; EqualValues_IDDepartment( long[]  values)
    {
        string? value=null;
        if(values.Length&gt;0)
            value=string.Join( ",",values);
        var sc=SearchDepartment.FromSearch(GeneratorFromDB.SearchCriteria.InArray,eDepartmentColumns.IDDepartment,value);
        await foreach (var item in _search.DepartmentFind_AsyncEnumerable(sc))
        {
         
            yield return (Department_Table)item!;
        }
    }
     [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; DifferentValues_IDDepartment( long[]  values)
    {
        string? value=null;
        if(values.Length&gt;0)
            value=string.Join( ",",values);
        var sc=SearchDepartment.FromSearch(GeneratorFromDB.SearchCriteria.NotInArray,eDepartmentColumns.IDDepartment,value);
        await foreach (var item in _search.DepartmentFind_AsyncEnumerable(sc))
        {
         
            yield return (Department_Table)item!;
        }
    }
         [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; EqualValue_IDDepartment( long  value)
    {
        var sc = GeneratorFromDB.SearchCriteria.Equal;
        await foreach (var item in _search.DepartmentSimpleSearch_IDDepartment(sc, value))
        {
            yield return (Department_Table)item!;
        }
    }
    [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; DifferentValue_IDDepartment( long  value)
    {
        var sc = GeneratorFromDB.SearchCriteria.Different;
        await foreach (var item in _search.DepartmentSimpleSearch_IDDepartment(sc, value))
        {
            yield return (Department_Table)item!;
        }
    }
    [HttpGet]
    public  async IAsyncEnumerable&lt;Department_Table&gt; SimpleSearch_IDDepartment(GeneratorFromDB.SearchCriteria sc,  long value){
        await foreach(var item in _search.DepartmentSimpleSearch_IDDepartment(sc,value))
        {
            yield return (Department_Table)item!;
        }
    }
    [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; FindNull_IDDepartment(){
        var sc = GeneratorFromDB.SearchCriteria.Equal;
        await foreach(var item in _search.DepartmentSimpleSearchNull_IDDepartment(sc))
        {
            yield return (Department_Table)item!;
        }
    }
    [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; FindNotNull_IDDepartment(){
        var sc = GeneratorFromDB.SearchCriteria.Different;
        await foreach(var item in _search.DepartmentSimpleSearchNull_IDDepartment(sc))
        {
            yield return (Department_Table)item!;
        }
    }
              [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; EqualValues_Name( string[]  values)
    {
        string? value=null;
        if(values.Length&gt;0)
            value=string.Join( ",",values);
        var sc=SearchDepartment.FromSearch(GeneratorFromDB.SearchCriteria.InArray,eDepartmentColumns.Name,value);
        await foreach (var item in _search.DepartmentFind_AsyncEnumerable(sc))
        {
         
            yield return (Department_Table)item!;
        }
    }
     [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; DifferentValues_Name( string[]  values)
    {
        string? value=null;
        if(values.Length&gt;0)
            value=string.Join( ",",values);
        var sc=SearchDepartment.FromSearch(GeneratorFromDB.SearchCriteria.NotInArray,eDepartmentColumns.Name,value);
        await foreach (var item in _search.DepartmentFind_AsyncEnumerable(sc))
        {
         
            yield return (Department_Table)item!;
        }
    }
         [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; EqualValue_Name( string  value)
    {
        var sc = GeneratorFromDB.SearchCriteria.Equal;
        await foreach (var item in _search.DepartmentSimpleSearch_Name(sc, value))
        {
            yield return (Department_Table)item!;
        }
    }
    [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; DifferentValue_Name( string  value)
    {
        var sc = GeneratorFromDB.SearchCriteria.Different;
        await foreach (var item in _search.DepartmentSimpleSearch_Name(sc, value))
        {
            yield return (Department_Table)item!;
        }
    }
    [HttpGet]
    public  async IAsyncEnumerable&lt;Department_Table&gt; SimpleSearch_Name(GeneratorFromDB.SearchCriteria sc,  string value){
        await foreach(var item in _search.DepartmentSimpleSearch_Name(sc,value))
        {
            yield return (Department_Table)item!;
        }
    }
    [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; FindNull_Name(){
        var sc = GeneratorFromDB.SearchCriteria.Equal;
        await foreach(var item in _search.DepartmentSimpleSearchNull_Name(sc))
        {
            yield return (Department_Table)item!;
        }
    }
    [HttpGet]
    public async IAsyncEnumerable&lt;Department_Table&gt; FindNotNull_Name(){
        var sc = GeneratorFromDB.SearchCriteria.Different;
        await foreach(var item in _search.DepartmentSimpleSearchNull_Name(sc))
        {
            yield return (Department_Table)item!;
        }
    }
         
 
 
     
 
 
}//end class

 

Finally , ExampleWebAPI . This will add the controllers from the ExampleControllers   to show the use .

1
2
3
4
var assControllers = typeof(UtilsControllers).Assembly;
builder.Services.AddControllers()
              .PartManager.ApplicationParts.Add(new AssemblyPart(assControllers)); ;
        

 

Of course , the name Example will be replaced , from the template, with the name of your project

.NET 7 Latest features

.NET 7 is a version of the .NET platform that was released on November 10, 2021. It is a major release that includes many new features and improvements. Some of the notable features of .NET 7 include:

Improved performance: .NET 7 includes many improvements that result in faster startup time and better overall performance.

Enhanced support for web development: .NET 7 includes several new features that make it easier to build web applications, including support for WebAssembly and a new HTTP client library.

Improved support for ARM64: .NET 7 includes better support for ARM64, allowing you to build applications that can run on devices with ARM processors.

New native interop API: .NET 7 includes a new native interop API that makes it easier to call native code from .NET applications.

Improved support for .NET MAUI: .NET MAUI is a cross-platform UI framework for building mobile, desktop, and cloud-based applications. .NET 7 includes several improvements to .NET MAUI, including a new Hot Reload feature and improved support for .NET 5.

For more information about .NET 7, you can visit the following links:

.NET 7 documentation: https://docs.microsoft.com/en-us/dotnet/standard/dotnet-7
.NET 7 release notes: https://github.com/dotnet/announcements/blob/master/releasedotnet/7/7.0.md

The previous lines were generated with ChatGPT , https://chat.openai.com/chat.  My presentation is at  https://ignatandrei.github.io/Presentations/WhatsNewNet7prez.html#1 with

  1. What’s new VS2022 ?

  2. What’s new C# 11
  3. What’s new Blazor
  4. What’s new ASP.NET Core 7
  5. What’s new EFCore 7
  6. Links

Rate Limiter–CORS limited

The problem is that , for the site ( Angular , React, plain HTML ) deployed into wwwroot of .NET Core, I want to have unlimited requests. Also, if I made requests to localhost ( when I try from local), I want also unlimited requests. However, if other site make requests to my AP( CORS enabled ) I, should have limited requests .

There is the Stefan Prodan package – https://github.com/stefanprodan/AspNetCoreRateLimit  . And in .NET Core 7 has appeared https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit  with 4 limiters  -please be sure that you read the article https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit .

Back to the problem:

So we have 2 limits; NoLimit if same site and a simple limiter( 3 request per minute )_ if coming via other site.

var noLimit = RateLimitPartition.GetNoLimiter(“”);

Func<string, RateLimitPartition<string>> simpleLimiter =
     (string address) =>
RateLimitPartition.GetFixedWindowLimiter(address, _ =>
{
     return new FixedWindowRateLimiterOptions()
     {
         PermitLimit = 3,
         Window = TimeSpan.FromMinutes(1),
         QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
         QueueLimit = 1
     };

});

Now, let’s see how we apply :

  1. verify if the host is unknown or  localhost – then no limit.
  2. verify if header has Origin key
    1. if has not – could be same site or desktop – then no limit ( if the xhr request to same site, Edge sends “Origin” header – Chrome does not! – same as desktop )
    2. if has – verify if it is the same with host
      1. if it is, then no limit
      2. if it is not, then simple limit
  3. return default simple limit

And this is the code

builder.Services.AddRateLimiter(opt =>
{
     opt.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
     opt.OnRejected = (ctx, ct) =>
     {
         ctx.HttpContext.Response.Headers.Add(“tiltLimit”, “please try later”);
         return ValueTask.CompletedTask;
     };
     opt.AddPolicy(“UnlimitMeAndLocalHost”, context =>
     {
        
         var host = context.Request.Host;
         var hostName = host.HasValue ? host.Host : “”;
         if (string.IsNullOrWhiteSpace(hostName))
         {
             Console.WriteLine(“no host???”);
             return simpleLimiter(“”);
         }
         if (string.Equals(hostName,”localhost”,StringComparison.InvariantCultureIgnoreCase))
         {
             Console.WriteLine(“localhost have no limit”);
             return noLimit;
         }
         //chrome does not send origin, if same site
         var hasOrigin = context.Request.Headers.TryGetValue(“Origin”, out var origin);
         //maybe also verify referer?
         if (!hasOrigin)
         {
             Console.WriteLine(“no origin -same site?”);
             return noLimit;

        }
         //edge sends origin
         var originHost = origin.ToString();
         //removing scheme
         if (originHost.StartsWith(“http://”))
         {
             originHost = originHost.Substring(7);
         }
         if (originHost.StartsWith(“https://”))
         {
             originHost = originHost.Substring(8);
         }
         var fullHost = context.Request.Host.Host;
         Console.WriteLine($”has origin {originHost} , full host {fullHost}”);
         if (string.Equals(fullHost,originHost, StringComparison.CurrentCultureIgnoreCase))
         {
             Console.WriteLine($”same site – no cors”);
             return noLimit;
         }
         //return noLimit;
         return simpleLimiter(origin.ToString());
     });

Pretty complicated – read again the algorithm above.

As a proof of concept , browse to https://ignatandrei.github.io/TILT/tilt/public  and to http://tiltwebapp.azurewebsites.net/AngTilt/ with developer tools open –  you will see 429 errors for the first, but not for the second.

And for seeing in action , execute 4 times fast this powershell

cls
$x=””
$hostName = “https://tiltwebapp.azurewebsites.net”
#$hostName = “http://localhost:9900″

$fullUrl = $hostName + “/api/PublicTILTs/LatestTILTs/ignatandrei/1”

$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$session.UserAgent = “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.62”
$x = Invoke-WebRequest -UseBasicParsing -Uri $fullUrl `
-WebSession $session `
-Headers @{
  “Origin” = “http://www.foo.com/”
“Accept-Encoding”=”gzip, deflate, br”
   “Accept-Language”=”en-US,en;q=0.9”
   “Referer”=”https://netcoreusefullendpoints.azurewebsites.net/swagger/index.html”
   “accept”=”application/json”
   “sec-ch-ua”=”`”Microsoft Edge`”;v=`”107`”, `”Chromium`”;v=`”107`”, `”Not=A?Brand`”;v=`”24`””
   “sec-ch-ua-mobile”=”?0″
   “sec-ch-ua-platform”=”`”Windows`””
}

$x.StatusCode
Write-Host ” ————————–“

NetCoreUsefullEndpoints–part 6–passing to .NET 7

So  .NET 7 has appeared and I decided to pass NetCoreUsefullEndpoints to .NET 7 .

Also, for RateLimiter , I have considered that is good to know if the request is local or remote … so I decided to add connection ( remote IP, local IP, and more details) to the nuget package.

So I have created for .NET 6 this :

So , first things first : modify the version from  6.2022.1203.1551 to  7.2022.1203.1551 ( my versioning scheme is .NETCore version compliant of the package.year.MMdd.HHmm  – pretty stable and easy to decide what package you should add)

Then I want to profit to show in swagger the return type with TypedResults – so , as an example , I have modified from

route.MapGet(“api/usefull/httpContext/Connection”, (HttpContext httpContext) =>
{
var con = httpContext.Connection;
if (con == null)
{
     return Results.NoContent();
}
var conSerialize = new
{
     LocalIpAddress = con.LocalIpAddress?.ToString(),
     RemoteIpAddress = con.RemoteIpAddress?.ToString(),
     con.RemotePort,
     con.LocalPort,
     con.ClientCertificate,
     con.Id
};
return Results.Ok(conSerialize);

})

to

route.MapGet(“api/usefull/httpContext/Connection”,

Results<NoContent, Ok<object>>
(HttpContext httpContext) =>
{
var con = httpContext.Connection;
if (con == null)
{
     return TypedResults.NoContent();
}
var conSerialize = new
{
     LocalIpAddress = con.LocalIpAddress?.ToString(),
     RemoteIpAddress = con.RemoteIpAddress?.ToString(),
     con.RemotePort,
     con.LocalPort,
     con.ClientCertificate,
     con.Id
};
return TypedResults.Ok((object)conSerialize);
})

As you see , a pretty easy modification – indicating the INesteHttpResult Results<NoContent, Ok<object>>  ( so the swagger understand the 2 different return types )  and returning TypedResults instead of Results

Also the github ci must add the .NET Core and Azure App Service should be going to .NET 7 STS

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.