This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

REST API - Updating an existing file

Good evening everyone,

let me introduce you to my problem with updating existing files and kindly ask you for a fix suggestion :)

You will probably notice that I am using an older REST-like API called MFWSClient.
A newer version was published on GitHub: https://github.com/M-Files/Libraries.MFWSClient on [color=blue]28.3.2020[/color], but due to reasons and hope this version will not be deprecated, I stick with it.

I have two questions. You will notice.

As the M-Files Developer portal similarly states on: https://developer.m-files.com/APIs/REST-API/Updating-Objects/#updating-an-existing-file
if one desires to update an existing file, the following should be done:

1. Authenticate: (my code below)

client = new MFClient(pURL);
client.Authentication = client.Post<PrimitiveType<string>>("/server/authenticationtokens", new Authentication { Username = pUsername, Password = pPassword, VaultGuid = pVaultGUID }).Value;
client.Authentication = client.Get<Vault>("/session/vault").Authentication;

Thanks to [color=green]SessionInfo[/color] I am able to check the user related information:

SessionInfo sessionInfo = client.Get<SessionInfo>("/session");
/*
Console.WriteLine("THE VALUES LISTED BELOW");

// Console output
sessionInfo.AccountName = ADMIN
sessionInfo.ACLMode = AutomaticPermissionsWithComponents
sessionInfo.AuthenticationType = SpecificMFilesUser
sessionInfo.CanForceUndoCheckout = True
sessionInfo.CanManageCommonUISettings = True
sessionInfo.CanManageCommonViews = True
sessionInfo.CanManageTraditionalFolders = True
sessionInfo.CanMaterializeViews = True
sessionInfo.CanSeeAllObjects = True
sessionInfo.CanSeeDeletedObjects = True
sessionInfo.InternalUser = True
sessionInfo.LicenseAllowsModifications = True
sessionInfo.UserID = 9
*/


It seems like I should be on the correct account as well as have the permissions to perform the desired activity.  :)

2. Check out an existing object: (my code below)

ObjectVersion objectVersion = client.Put<ObjectVersion>(string.Format("/objects/{0}/{1}/{2}/checkedout", pType, pObjectID, pVersion),
                                                                                  new PrimitiveType<MFCheckOutStatus>() { Value = MFCheckOutStatus.CheckOutToMe });

Thanks to [color=green]ObjectVersion[/color] I am able to check the object related information:

ObjectVersion objectVersion = client.Get<ObjectVersion>(string.Format("/objects/{0}/{1}/{2}", pType, pObjectID, pVersion));
/*
Console.WriteLine("THE VALUES LISTED BELOW");

// Console output
objectVersion.CheckedOutToUserName = Administrator
objectVersion.CheckedOutTo = 9
objectVersion.ObjectCheckedOut = True
objectVersion.ObjectCheckedOutToThisUser = True
*/

Looking at the console, it seems like the object was checked out to me.  :)
[color=red]But looking at M-Files Explorer it is apparently not - Please see the image:[/color] https://imgur.com/MUlhhIg

Question #1. What did I do wrong here?

3. Prepare and update / upload a file: (my code below)

ObjectFile[] files = client.Get<ObjectFile[]>(string.Format("/objects/{0}/{1}/{2}/files", pType, pObjectID, pVersion));
if (files.Length == 0) return;
/*
DownloadFileAsStream(); <- I was able to extract the code for this from the new MFWSClient API. The older one did not provide this functionality.
ConvertFileToReadableFormat();
SaveFileOnHardDrive();
OpenAndEditFile();
*/

ObjectVersion objectVersion = client.Put<ObjectVersion>(string.Format("/objects/{0}/{1}/{2}/files/{3}/content", pType, pObjectID, pVersion, files[0].ID),
                                                    new System.Net.Http.StreamContent(new FileInfo(Path.GetFullPath(pFilePath)).OpenRead()));


I am aware the last REST-like call might not be entirely correct,
but I did my best to search for the right examples on the M-Files Documentation sources,
but I have to say that some of them are missing or not matching the API publised on GitHub.
I apologize if I missed anything and will be grateful for a hint on this one.

Question #2. What is the correct way?
(I see a lot of forums that mention: "application/octet-stream" with posting random binary formatfiles across the interwebs)
(I also noticed the client.Put<T>(); method originally does not account for this)

4. Check back in (not important in this context)

Thank you a lot M-Files staff & fellow developers, perhaps this post is useful to other newcomers as well.

Edit:
This is the method performing the GET / PUT requests:


public T Get<T>(string pPath) {
    return (T)PerformRequest("GET", pPath, null, typeof(T));
}
public T Put<T>(string pPath, object pContent) {
    return (T)PerformRequest("PUT", pPath, pContent, typeof(T));
}
private object PerformRequest(string pMethod, string pPath, object pContent, Type pReturnType) {
    if (pPath[0] == '/')
        pPath = pPath.Substring(1);
        string uri = EndPoint + pPath;
        if (pMethod == "PUT" || pMethod == "DELETE") {
            if (uri.Contains("?")) uri += "&";
            else uri += "?";
            uri += "_method=" + pMethod;
        }
        WebRequest request = WebRequest.Create(uri);
        request.Method = (pMethod.ToUpper() == "GET") ? "GET" : "POST";
        if (!string.IsNullOrEmpty(Authentication)) request.Headers["X-Authentication"] = Authentication;
        if (pContent != null) {
            if (pContent is Stream) {
                Stream requestStream = request.GetRequestStream();
                Stream sourceStream = (Stream)pContent;
                sourceStream.CopyTo(requestStream);
                requestStream.Flush();
                requestStream.Close();
            } else {
                Stream requestStream = request.GetRequestStream();
                DataContractJsonSerializer requestSerializer = new DataContractJsonSerializer(pContent.GetType());
                requestSerializer.WriteObject(requestStream, pContent);
                requestStream.Flush();
                requestStream.Close();
            }
        }
        WebResponse response;
        try {
            response = request.GetResponse();
        } catch (WebException pException) {
            HandleError(pException);
            throw;
        }
        if (pReturnType == null) return null;
        if (pReturnType == typeof(string)) return new StreamReader(response.GetResponseStream()).ReadToEnd();
        if (pReturnType == typeof(Stream)) return response.GetResponseStream();
        if (response.GetResponseStream() == null) return null;
        return new DataContractJsonSerializer(pReturnType).ReadObject(responseStream);
}
Parents

  • 1. I do indeed check the object out using REST-API and then view it's status in the M-Files Desktop Client.
    but the credentials used for logging to M-Files Desktop Client as well as to retrieve the authentication token for REST-API are the same. Exactly same user.
    Perhaps the REST-like access is also distinguished from the M-Files Desktop-like access? And that would be why the object seems to be checked out to someone else even though I view it under same login credentials?


    Yes. A checkout is computer-specific. As I said in the example: if you checked out an object on computer A, then accessed M-Files from computer B then it would show as checked out by someone else. In this case you are checking out the object via the REST API ("computer A"), then viewing it via the desktop client ("computer B"). So it shows that it's checked out as your user, but via "WWW" (the REST API).


    2. I did not get to concluding the second scenario, because I was always getting an Exception: "Object is already checked out" or "Object is reserved"
    Same applies here, same login credentials on both platforms. And I was not sure if it is caused by the problem in the first question or not..therefore I can not adjust my approach to resolving it.


    I'm not entirely sure what you mean here. The correct sequence should be:
    [list type=decimal]
    • Execute a request to check out the object via the REST API.

    • Execute a update-file-contents request via the REST API.

    • Execute a request to check in the object via the REST API.

    [/list]

    I think you are going to need to show us the exact HTTP requests (not the code; the actual HTTP request) that you're making, and the exact responses that you receive.

    Regards,

    Craig.
Reply

  • 1. I do indeed check the object out using REST-API and then view it's status in the M-Files Desktop Client.
    but the credentials used for logging to M-Files Desktop Client as well as to retrieve the authentication token for REST-API are the same. Exactly same user.
    Perhaps the REST-like access is also distinguished from the M-Files Desktop-like access? And that would be why the object seems to be checked out to someone else even though I view it under same login credentials?


    Yes. A checkout is computer-specific. As I said in the example: if you checked out an object on computer A, then accessed M-Files from computer B then it would show as checked out by someone else. In this case you are checking out the object via the REST API ("computer A"), then viewing it via the desktop client ("computer B"). So it shows that it's checked out as your user, but via "WWW" (the REST API).


    2. I did not get to concluding the second scenario, because I was always getting an Exception: "Object is already checked out" or "Object is reserved"
    Same applies here, same login credentials on both platforms. And I was not sure if it is caused by the problem in the first question or not..therefore I can not adjust my approach to resolving it.


    I'm not entirely sure what you mean here. The correct sequence should be:
    [list type=decimal]
    • Execute a request to check out the object via the REST API.

    • Execute a update-file-contents request via the REST API.

    • Execute a request to check in the object via the REST API.

    [/list]

    I think you are going to need to show us the exact HTTP requests (not the code; the actual HTTP request) that you're making, and the exact responses that you receive.

    Regards,

    Craig.
Children
No Data