Mapster icon indicating copy to clipboard operation
Mapster copied to clipboard

Updated version numbers to 9.0.0-pre02. + net 10

Open DocSvartz opened this issue 2 months ago โ€ข 10 comments

DocSvartz avatar Oct 31 '25 17:10 DocSvartz

@andrerav I can not use Mapster because its requiring net7:

Framework: 'Microsoft.NETCore.App', version '7.0.0' (x64)

would you maybe check if you are able to merge this (hopefully fixing) PR ?

DevTKSS avatar Nov 26 '25 19:11 DevTKSS

https://devblogs.microsoft.com/dotnet/dotnet-7-end-of-support/

stagep avatar Nov 26 '25 19:11 stagep

@DevTKSS If you are using net 8.0 or net 9.0, you can try use Mapster 9.0.0-pre01. Include Breaking changes after 9.0.0-pre01 to the Mapster library are not planned.

DocSvartz avatar Nov 27 '25 04:11 DocSvartz

@DocSvartz I am using the latest pre release that's available for all nugets and tool too, but the tool keeps failing with telling me I would need to install the net7 runtime workload which shouldn't be required. As there is no simple source generator package available as replacement alternative seems like I will have to search a different NuGet or dotnet tool for mapping or keep writing Dtos ๐Ÿคท

DevTKSS avatar Nov 27 '25 07:11 DevTKSS

Are you using Mapster and/or Mapster.Tool? As @DocSvartz mentioned, older versions supported .Net 7. The worse case scenario is forking and adding back in .Net 7. We are here to help you find a solution / workaround.

stagep avatar Nov 27 '25 12:11 stagep

@stagep I figured it out, but the Wiki was not very helpfull in this ๐Ÿ˜… Could you at least update this? Just in case you might want to improve the User Expirience, feel free to share this setup in your docs with your other users ๐Ÿ‘

A part of the problem was also that, while you "just" used the &quote; for " I would have prefered a small Note box to not get an headache by not seeing this small difference ๐Ÿ˜…

I additionally installed it globally, but more out of always typing -g for the other dotnet tool I am using ๐Ÿ˜„ dotnet-tools.json:

{
  "version": 1,
  "isRoot": true,
  "tools": {
    "mapster.tool": {
      "version": "9.0.0-pre01",
      "commands": [
        "dotnet-mapster"
      ],
      "rollForward": true,
      "allowPrerelease": true
    }
  }
}

This is what I came up with using Directory.Build.targets alongside with minimal csproj and Directory.Packages.props usage as my Solution uses CPM:

Directory.Packages.props

  <ItemGroup Label="Mapping">
    <PackageVersion Include="Mapster" Version="9.0.0-pre01" />
    <PackageVersion Include="Mapster.DependencyInjection" Version="9.0.0-pre01" />
    <PackageVersion Include="Mapster.Async" Version="9.0.0-pre01" />
    <PackageVersion Include="Mapster.Immutable" Version="9.0.0-pre01" />
    <PackageVersion Include="Mapster.EFCore" Version="9.0.0-pre01" />
  </ItemGroup>

Directory.Build.targets

<Project>
  <!--
    Mapster integration targets.
  
    Mapster integration targets.
    Usage:
      1) Run one-time setup (executes dotnet tool restore in repo root):
         msbuild -t:MapsterSetup
      2) Enable per-project automatic Mapster generation by adding to the project's .csproj:
         <PropertyGroup>
           <MapsterEnabled>true</MapsterEnabled>
         </PropertyGroup>
    3) Optionally, specify the Mapster generated files path pattern e.g. if you want to see the files in the project directory:
        <ProjectProperties>
          <MapsterPath>$(ProjectDir)**\mapster\**\*.g.cs</MapsterPath>
        </ProjectProperties>

        And include the following ItemGroup to expose the generated files in the project:
        <ItemGroup Label="Include Mapster Generated Files" Condition="'$(MapsterEnabled)' == 'true' and Exists('$(BaseIntermediateOutputPath)mapster')">
          <Compile Remove="$(MapsterPath)" />
          <None Include="$(MapsterPath)">
            <Link>mapster-generated/$(RecursiveDir)%(Filename)%(Extension)</Link>
            <Visible>true</Visible>
          </None>
        </ItemGroup>

    4) Build the project. If MapsterEnabled is true and the project includes a net9.0 target framework, Mapster code generation will run after build.
       as the code generated is not runtime-specific, it will be generated once per project, not per TFM.
       This way you can also use the generated files in multiple TFMs e.g. net10.0 while dotnet-mapster only supports up to net9.0 currently.
         -->
  <Target Name="MapsterSetup">
    <!-- Run tool restore in repository root (parent of /src). Only report on failure to avoid noise. -->
    <Exec WorkingDirectory="$(MSBuildThisFileDirectory).." Command="dotnet tool restore" Condition="Exists('$(MSBuildThisFileDirectory)..\.config\dotnet-tools.json')" ContinueOnError="true">
      <Output TaskParameter="ExitCode" PropertyName="MapsterSetupExitCode" />
    </Exec>
    <Error Text="MapsterSetup: dotnet tool restore failed (exit code $(MapsterSetupExitCode))."
           Condition="Exists('$(MSBuildThisFileDirectory)..\.config\dotnet-tools.json') and '$(MapsterSetupExitCode)' != '' and '$(MapsterSetupExitCode)' != '0'" />
  </Target>

  <!-- Run Mapster only when project targets net9.0 (either current TFM or TargetFrameworks contains net9.0). -->
  <Target Name="Mapster" AfterTargets="AfterBuild"
          Condition="'$(MapsterEnabled)' == 'true' and ( '$(TargetFramework)' == 'net9.0' or $([System.String]::Copy('$(TargetFrameworks)').Contains('net9.0')) == 'True' )" >

    <Message Importance="high" Text="Mapster: starting code generation for $(MSBuildProjectName)..." />

    <!-- Generate into a non-runtime-specific obj/mapster folder to allow reuse across TFMs -->
    <Exec WorkingDirectory="$(MSBuildProjectDirectory)"
          Command="dotnet mapster model -a &quot;$(TargetPath)&quot; -o &quot;$(BaseIntermediateOutputPath)mapster&quot; -r -N"
          ContinueOnError="false" />

    <Exec WorkingDirectory="$(MSBuildProjectDirectory)"
          Command="dotnet mapster extension -a &quot;$(TargetPath)&quot; -o &quot;$(BaseIntermediateOutputPath)mapster&quot; -N"
          ContinueOnError="false" />

    <Exec WorkingDirectory="$(MSBuildProjectDirectory)"
          Command="dotnet mapster mapper -a &quot;$(TargetPath)&quot; -o &quot;$(BaseIntermediateOutputPath)mapster&quot; -N"
          ContinueOnError="false" />
    
    <Message Importance="high" Text="Mapster: finished generation for $(MSBuildProjectName)." />
  </Target>
  <ItemGroup>
    <GeneratedMappings Include="**\\mapster\\*.g.cs" />
  </ItemGroup>

  <Target Name="CleanGenerated" BeforeTargets="Clean">
    <Message Importance="low" Text="CleanGenerated: removing mapster generated files..." Condition="Exists('$(BaseIntermediateOutputPath)mapster')" />
    <Delete Files="@(GeneratedMappings)" ContinueOnError="false" Condition="Exists('$(BaseIntermediateOutputPath)mapster')" />
  </Target>
</Project>

the Project file .csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <RootNamespace>DevTKSS.MyProject.DataContracts</RootNamespace>
    <AssemblyName>DevTKSS.MyProject.DataContracts</AssemblyName>
    <!-- The Dependending Projects are already migrated to .net10.0 so the net9.0 is only to enable dotnet-mapster -->
    <TargetFrameworks>net9.0;net10.0</TargetFrameworks>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <MapsterEnabled>true</MapsterEnabled>
    <MapsterPath>$(ProjectDir)**\mapster\**\*.g.cs</MapsterPath>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Mapster" />
    <PackageReference Include="Mapster.DependencyInjection" />
    <PackageReference Include="Mapster.Async" />
    <PackageReference Include="Mapster.Immutable" />
    <PackageReference Include="Mapster.EFCore" />
  </ItemGroup>

  <!-- Mapster generated files: expose as visible None items and set DependentUpon to the source file when possible -->
  <ItemGroup Label="Include Mapster Generated Files" Condition="'$(MapsterEnabled)' == 'true' and Exists('$(BaseIntermediateOutputPath)mapster')">
    <Compile Remove="$(MapsterPath)" />
    <None Include="$(MapsterPath)">
      <Link>mapster-generated/$(RecursiveDir)%(Filename)%(Extension)</Link>
      <Visible>true</Visible>
    </None>
  </ItemGroup>
</Project>

By the way, refering to your Mapster.Tool Wiki Page this -r should generate Record types but you are not mentioning that only the dotnet-mapster model command actually supports it reading the Options in the src! Maybe this should be told and not generalized listed for all of the commands.

image

The actual src/Mapster.Tool/MapperOptions.cs and ExtensionOptions.csdoesn't contain this Option either and resulting from that, its unknown to the compiled dotnet tool we are getting and produces this Error:

Mapster.Tool 9.0.0-pre01+998402908cdc59d2bbdbab5fbc1d5062153494e8
1>  Copyright (c) 2025 Chaowlert Chaisrichalermpol, Eric Swann, Andreas Ravnestad
1>
1>  ERROR(S):
1>    Option 'r' is unknown.
1>  USAGE:
1>  Generate extensions:
1>    dotnet mapster extension mapper --assembly /Path/To/YourAssembly.dll --output
1>    Models
1>
1>    -a, --assembly             Required. Assembly to scan
1>
1>    -o, --output               (Default: Models) Output directory.
1>
1>    -n, --namespace            Namespace for extensions
1>
1>    -p, --printFullTypeName    Set true to print full type name
1>
1>    -b, --baseNamespace        Provide base namespace to generate nested output &
1>                               namespace
1>
1>    -s, --skipExisting         Set true to skip generating already existing files
1>
1>    -N, --nullableDirective    Set true to add "#nullable enable" to the top of
1>                               generated extension files
1>
1>    --help                     Display this help screen.
1>
1>    --version                  Display version information.

but I am not sure from the Attribute docs of mapster, if there might be one of the arguments that I am missing but cases like this: image

are generating this: image

while expected would be the summary to actually optional (missing = null or = "") and the TemperatureF ... not sure is this a case for your IgnoreAttribute? but then I would also not get this to be readable. I dont see a way to exclude some from the ctor but still include them as { get; } while it should be keeping the code that is setting the property๐Ÿคท This here would be a possible expectation:

/// <summary>
/// A Weather Forecast for a specific date
/// </summary>
/// <param name="Date">Gets the Date of the Forecast.</param>
/// <param name="TemperatureC">Gets the Forecast Temperature in Celsius.</param>
/// <param name="Summary">Get a description of how the weather will feel.</param>
public record WeatherForecastQuery(DateOnly Date, double TemperatureC, string? Summary = null)
{
    /// <summary>
    /// Gets the Forecast Temperature in Fahrenheit
    /// </summary>
    public double TemperatureF => 32 + (TemperatureC * 9 / 5);
}

Maybe you could check on this and add it to any kind of back log?

DevTKSS avatar Nov 28 '25 02:11 DevTKSS

I'm very glad that you managed to solve this ๐Ÿคฉ Don't be shy about opening an issue on topics that interest you.

If i understand correctly, it is Business logic:

public double TemperatureF => 32 + (TemperatureC * 9 / 5);

Dtos shouldn't contain Business logic, but simply serve to transfer data.

I dont see a way to exclude some from the ctor but still include them as { get; } while it should be keeping the code that is setting the property๐Ÿคท

Yes, there is a problem with that.

Also keep in mind that the record types in the Mapster Wiki are not actually equal Records in C# .

Records mapping has already been added in Mapster, but there is no generation with MapsterTool yet.

DocSvartz avatar Nov 28 '25 09:11 DocSvartz

@DocSvartz ๐Ÿค”๐Ÿ˜… assumed they are the same! Will look again into this. Can you tell how someone could contribute to such wiki ? I always used to contribute to md files produced by docfx for example also set one up for my own samples repo๐Ÿค” I just seen your much issues load and thought you would just only want to stay where you are and keep it stable as possible but not proceeding, which would be quite sad because I would see your NuGet as great and most maintained alternative to AutoMapper which seems to require payment and I prefer staying on OSS or similar projects and if I see problems with something I tend to checkig if I can help with it and (if yes) contribute with a PR because I know that beyond every good Dev potentially is also ๐Ÿ‘€ (hope so at least ๐Ÿ˜œ) a life or/and a family to care for beside creating great stuff ๐Ÿ˜

DevTKSS avatar Nov 28 '25 10:11 DevTKSS

@DocSvartz and one question to the PR here: What is the reason for your don't want to upgrade or add the new tfm's? Is it just for the review time you maybe not have, or what is blocking you from sending even the net9 into stable version release? Reasons I could imagine...

  • specific issues
  • test coverage
  • ?

DevTKSS avatar Nov 28 '25 10:11 DevTKSS

@DevTKSS
about Wiki - I haven't edited the wiki yet either, so I can't offer any advice. ๐Ÿ˜”

I and @stagep recently joined the Mapster. I am adding new features from issue or fix bugs, but i am not by publishing new versions.

See this discussion and contact @andrerav if you want to become one of maintainers Mapster.

In fact, quite a lot of changes have accumulated since version 7.4.0, There was one big problem and a lot of changes associated with it :).

DocSvartz avatar Nov 28 '25 11:11 DocSvartz

update to #841

DocSvartz avatar Dec 22 '25 09:12 DocSvartz