Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • crono 58 posts 129 karma points
    Aug 03, 2017 @ 19:54
    crono
    0

    Update member property inbetween file uploads

    Hi,

    I'm trying to add a limit to the amount of files a member can upload. But I can't seem to update the property of the member - that holds the value for how many files the member has uploaded - while the upload of multiple files is happening.

    When the member uploads a file, I get the current IMember and increment the 'Count' value by one, and then save the member.

    When the next file comes along, the 'Count' value has not been updated in the database yet, so the 'Count' stays unchanged when incremented.

    I tried all sorts of ways to read/write the data before the 2nd file gets uploaded, but to no avail. Thought about writing a file to disk, but IO probably has the same issue as writing to the database, and I'd rather have all that data in the database anyway.

    So, what to do? Am I doing it completely wrong in the first place, or is there a fancy solution for this kind of problem?

    This is what I'd like to do:

     var m = ApplicationContext.Current.Services.MemberService.GetById(member.Id);
     int fileCount = m.GetValue<int>("fileCount");
     fileCount += 1;
     m.SetValue("fileCount", fileCount);
     ApplicationContext.Current.Services.MemberService.Save(m);
    
  • John Bergman 483 posts 1132 karma points
    Aug 03, 2017 @ 20:55
    John Bergman
    0

    Does it ever get updated?

  • crono 58 posts 129 karma points
    Aug 03, 2017 @ 21:27
    crono
    0

    Yes, after the first few httprequests..

    The frontend js script throttles the amount of simultaneous uploads at a time to 3. If I upload 3 files, the count increases by 1. If I upload more files, the count is always 2 less than the amount of files uploaded.

    I suspect that it is happening because the first 3 files that get added to the queue are "grouped" when sent with ms appart, whereas the remaining files are seconds appart, resulting in new requests with updated values.

    The controller code is not complicated:

     [HttpPost]
     public JsonResult UploadFile(HttpPostedFileBase file, int parentId)
     {  
          var member = Members.GetCurrentMember();
    
          if (member != null)
          {
               var m = ApplicationContext.Current.Services.MemberService.GetById(member.Id);
               int fileCount = m.GetValue<int>("fileCount");
               fileCount += 1;
               m.SetValue("fileCount", fileCount);
               ApplicationContext.Current.Services.MemberService.Save(m);
          }
          return ToJson(1);
    
     }
    
  • John Bergman 483 posts 1132 karma points
    Aug 04, 2017 @ 14:55
    John Bergman
    1

    So you have a threading issue. the value is read from multiple threads, and the last one in is what you see as far as updating the value.

    There are several ways to handle this, from putting a lock around the C# code to wrapping the code in a transaction to throttling on the client side.

  • crono 58 posts 129 karma points
    Aug 04, 2017 @ 20:38
    crono
    0

    That was my first thought as well, just didn't know how to get around it.

    Not too happy about adding a lock, and throttling it on the client will just open a door to potentially exploit it =/

  • Sebastiaan Janssen 5045 posts 15476 karma points MVP admin hq
    Aug 04, 2017 @ 15:12
    Sebastiaan Janssen
    1

    Please please please please do not update properties with a counter on members, content or media. it just leads to a complete copy of all property data on the specific item to be stored all over again. This very quickly increases the amount of rows in cmsPropertyData making your database grow really fast.

    Counters should be maintained somewhere else, always. Consider a database table with two columns: member ID and upload count.

    This is covered in the documentation about common pitfalls too: https://our.umbraco.org/Documentation/Reference/Common-Pitfalls/#using-umbraco-content-items-for-volatile-data

  • crono 58 posts 129 karma points
    Aug 04, 2017 @ 20:36
    crono
    0

    Yea, thought about that too..

    I tried creating a new table for storing just that data, but the 'refresh' of the database content still 'lags behind'. Tried it on both the main umbraco database and a secondary MySQL one.

    Doesn't matter if I use the DatabaseContext or a new SqlConnection.

  • John Bergman 483 posts 1132 karma points
    Aug 04, 2017 @ 21:04
    John Bergman
    1

    Its not about the connection, it is about the transaction. If you use a separate table, wrap the code that updates it in a transaction, that way any additional calls are blocked until the transaction completes, and that should take care of your issue.

  • crono 58 posts 129 karma points
    Aug 04, 2017 @ 21:45
    crono
    0

    Cool, I'll give that a go. Thanks a lot :D

Please Sign in or register to post replies

Write your reply to:

Draft