Reza245
Reza245

Reputation: 97

returning entity model property with extra string

I have an ASP.NET Core 8 Web API using Dapper as ORM.

This is my entity class:

namespace Server.Entities
{
    public class Post
    {
        public int Id { get; set; } 
        public string Title { get; set; } 
        public string Slug { get; set; } 
        public int CategoryId { get; set; } 
        public bool Bookmarked = false;
        public bool Liked = false;
        public bool Premium { get; set; }
        public string BriefText { get; set; } 
        public string Text { get; set; }
        public string CoverImage { get; set; } 
        public int ReadingTime { get; set; }
        public Collection<string> Tags = new Collection<string>();
        public int Author { get; set; } 
        public Collection<Post> Relateds = new Collection<Post>();
        public Collection<Comment> Comments = new Collection<Comment>();
    }

    public class PostDTO
    {
        public string Title { get; set; }
        public string Slug { get; set; }
        public string CoverImage { get; set; }
        public string Text { get; set; }
    }
}

Here's my controller:

 [HttpGet]
 public async Task<ActionResult> GetAllPosts()
 {
    PostDTO[] posts = await _dbContext.Post.GetAllAsync();
    return Ok(posts);
 }

And my service:

 public async Task<PostDTO[]> GetAllAsync()
 {
    string query = "SELECT * FROM Posts";
    IEnumerable<PostDTO> posts = await _connection.QueryAsync<PostDTO>(query);
    return posts.ToArray();
 }

As you see I return PostDTO to the client, the CoverImage property is an image URL without domain name, like this:

 /uploads/coverImage/2024/7/10/1723272284733-718853888.jpg

For using this url in frontend, I have to add the domain before the URL. Is there any way to combine the domain automatically with the property before sending it to client?

I used this:

public class PostDTO
{
    public string Title { get; set; }
    public string Slug { get; set; }

    public string CoverImage { get; set; }
    public string CoverImageURL
    {
        get => "http://localhost:8000" + CoverImage;
        set => CoverImage = value;
    }
    public string Text { get; set; }
}

This way I would have a full image URL, but I think it's not a good idea to return an extra property to client.

What if I modify the main property CoverImage to return the full URL as shown here:

public class PostDTO
{
    public string Title { get; set; }
    public string Slug { get; set; }

    public string CoverImage
    {
        get => "http://localhost:8000" + CoverImage;
        set => CoverImage = value;
    }
    public string Text { get; set; }
}

Using this, I get an error from Dapper:

info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[102]
Route matched with {action = "GetAllPosts", controller = "Post"}. Executing controller action with signature System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.ActionResult] GetAllPosts() on controller Server.Controllers.PostController (server). Stack overflow. Repeat 24234 times:

at Server.Entities.PostDTO.set_CoverImage(System.String)
at DynamicClass.Deserializedeb5d960-6b33-4fce-84f4-e8ee01aaac3a(System.Data.Common.DbDataReader)
at Dapper.SqlMapper+d__331[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext() at System.Runtime.CompilerServices.AsyncTaskMethodBuilder1+AsyncStateMachineBox1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Dapper.SqlMapper+<QueryAsync>d__331[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Dapper, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]].ExecutionContextCallback(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder1+AsyncStateMachineBox1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e], Dapper.SqlMapper+d__331[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Dapper, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext(System.Threading.Thread) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder1+AsyncStateMachineBox1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e], Dapper.SqlMapper+<QueryAsync>d__331[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Dapper, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Runtime.CompilerServices.IAsyncStateMachineBox, Boolean)
at System.Threading.Tasks.Task.RunContinuations(System.Object)
at System.Threading.Tasks.Task.FinishSlow(Boolean)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread)
at System.Threading.Tasks.ThreadPoolTaskScheduler.TryExecuteTaskInline(System.Threading.Tasks.Task, Boolean)
at System.Threading.Tasks.TaskScheduler.TryRunInline(System.Threading.Tasks.Task, Boolean)
at System.Threading.Tasks.TaskContinuation.InlineIfPossibleOrElseQueue(System.Threading.Tasks.Task, Boolean)
at System.Threading.Tasks.ContinueWithTaskContinuation.Run(System.Threading.Tasks.Task, Boolean)
at System.Threading.Tasks.Task.RunContinuations(System.Object)
at System.Threading.Tasks.Task1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TrySetResult(System.__Canon) at System.Threading.Tasks.UnwrapPromise1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TrySetFromTask(System.Threading.Tasks.Task, Boolean)
at System.Threading.Tasks.UnwrapPromise`1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ProcessInnerTask(System.Threading.Tasks.Task)
at System.Threading.Tasks.Task.RunContinuations(System.Object)
at System.Threading.Tasks.Task.FinishSlow(Boolean)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread)
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart()

Upvotes: 0

Views: 60

Answers (1)

Brando Zhang
Brando Zhang

Reputation: 28302

This SO issue is related with the CoverImage set method call itself which caused this issue.

To solve this issue, I suggest you could write a new property which will create the full local string.

More details, you could refer to below example:

PostDTO:

public class PostDTO
{
    public string Title { get; set; }
    public string Slug { get; set; }

  
    private string _coverImage;

 
    public string CoverImage
    {
        get => _coverImage;
        set => _coverImage = value;
    }

     public string FullCoverImageURL
    {
        get => "http://localhost:8000" + _coverImage;
    }

    public string Text { get; set; }
}

Usage:

        var connectionString = @"xx";

        using var conn = new SqlConnection(connectionString);
        string query = "SELECT * FROM Posts";
        IEnumerable<PostDTO> posts =   conn.Query<PostDTO>(query);
        var result= posts.ToArray();

        return Ok(result);

Result:

enter image description here

enter image description here

Upvotes: 1

Related Questions