1

I have an async task for getting messages via entity framework, but I also need to compute the username of senders and recipients. To do this I have a second async task that gets the IdentityUser object for the user by userid and then gets the username for that id.

For instance:

public async Task<Messages[]> GetMessages()
        {
            return await (from message in _context.Messages
                          select message into msg
                          select new Messages
                          {
                              Messageid = msg.Messageid,
                              Subject = msg.Subject,
                              Recipient = msg.Recipient,
                              Sender = msg.Sender,
                              Date = msg.Date,
                              Msgsender = MsgUserName(msg.Sender).Result,
                              Msgrecipient = MsgUserName(msg.Recipient).Result
                          }).ToArrayAsync();
        }

That task works for getting messages, but then I need to figure out usernames based on user ids.

public async Task<string> MsgUserName(string userid)
        {
            IdentityUser user = await _userManager.FindByIdAsync(userid);
            return await _userManager.GetUserNameAsync(user);
        }

This results in the following error message at runtime: InvalidOperationException: The client projection contains a reference to a constant expression of 'PostAlmostAnything.SiteServices.MessageService' through the instance method 'MsgUserName'. This could potentially cause a memory leak; consider making the method static so that it does not capture constant in the instance. See https://go.microsoft.com/fwlink/?linkid=2103067 for more information.

I tried making it static per the recommendation, but that results in a red squiggly line under _userManager and the error message "An object reference is required for the nonstatic field, method, or property 'MessageService._userManager'"

I figure there are probably two ways around this. Find a way to make the user manager accessible via a static method or find a way to make .Net ignore the potential memory leak and run anyway.

I don't see how this would result in a memory leak. I'm just getting usernames by id for every message.

  • 1
    **Never** use `.Result` in a `Task`. Use `await` instead. – Alejandro Aug 06 '21 at 02:04
  • 1
    This is where Navigation properties save you from all that confusing jazz. Message should have navigation properties to resolve a reference to the associated sender and recipient. Then you can just project down to get Sender.UserName and Recipient.UserName rather than making repeated singular queries for each results. (As bad as lazy loading, if not worse) – Steve Py Aug 06 '21 at 02:17
  • I would use navigation properties if I were using one of my models and not the built in IdentityUser model. – WannabePuppetMaster Aug 06 '21 at 02:47
  • I tried passing the UserManager as an object like this question says https://stackoverflow.com/questions/53518688/net-core-2-1-accessing-config-usermanager-in-a-static-helper but that led to a new error which says AggregateException: One or more errors occurred. (There is already an open DataReader associated with this Connection which must be closed first.) InvalidOperationException: There is already an open DataReader associated with this Connection which must be closed first. – WannabePuppetMaster Aug 06 '21 at 03:05
  • Alejandro, removing .Result causes a red squiggly line with a Compiler Error CS0029 message saying that you cannot implicitly convert type System.Threading.Task to string. Adding "await" in front of MsgUserName(msg.Sender) creates a CS1995 error saying the await operator can only be used in a query expression within the first collection expression of the initial from clause or within the collection expression of a join clause. – WannabePuppetMaster Aug 06 '21 at 03:39
  • 1
    @WannabePuppetMaster Have you referred to [this answer](https://stackoverflow.com/a/35016869)? Along side your idea, I think it may help you. And I think you may divide the `MsgUserName` from you linq query to benefit the expanding of business logic. – Tiny Wang Aug 06 '21 at 09:33
  • The approach I am taking now is to implement the ApplicationUser models described at https://learn.microsoft.com/en-us/aspnet/core/security/authentication/customize-identity-model?view=aspnetcore-5.0 and then I'll be adding navigation between the messages and user tables – WannabePuppetMaster Aug 07 '21 at 21:34
  • After implementing the ApplicationUser class I tried accessing the UserName as a navigation property, but am served with an error saying "Navigation properties can only participate in a single relationship" it seems the problem is that I have two relationships between ApplicationUser and Messages because each message has a sender and a recipient, so I need two navigation properties between the user id of the sender and the user id of the recipient. – WannabePuppetMaster Aug 08 '21 at 01:27

1 Answers1

-1

It seems Steve Py's comment put me on the right track. I implemented a custom ApplicationUser via these instructions https://learn.microsoft.com/en-us/aspnet/core/security/authentication/customize-identity-model?view=aspnetcore-5.0 and was able to access the UserName of both senders and recipient as navigation properties.

  • Please don't link to external sites as answers. Always put the content required directly in your answer. Only link to provide supporting evidence. – Enigmativity Aug 08 '21 at 02:54