protected function do_context_membership_request(Context $context, ResourceLink $resourcelink = null,
                                                     $membershipsurltemplate = '') {
        $dataconnector = $this->dataconnector;

        // Flag to indicate whether to save the context later.
        $contextupdated = false;

        // If membership URL is not set, try to generate using the default membership URL from the consumer profile.
        if (!$context->hasMembershipService()) {
            if (empty($membershipsurltemplate)) {
                mtrace("Skipping - No membership service available.\n");
                return false;
            }

            if ($resourcelink === null) {
                $resourcelink = $dataconnector->get_resourcelink_from_context($context);
            }

            if ($resourcelink !== null) {
                // Try to perform a membership service request using this resource link.
                $resourcelinkmembers = $this->do_resourcelink_membership_request($resourcelink);
                if ($resourcelinkmembers) {
                    // If we're able to fetch members using this resource link, return these.
                    return $resourcelinkmembers;
                }
            }

            // If fetching memberships through resource link failed and we don't have a memberships URL, build one from template.
            mtrace("'custom_context_memberships_url' not set. Fetching default template: $membershipsurltemplate");
            $membershipsurl = $membershipsurltemplate;

            // Check if we need to fetch tool code.
            $needstoolcode = strpos($membershipsurl, '{tool_code}') !== false;
            if ($needstoolcode) {
                $toolcode = false;

                // Fetch tool code from the resource link data.
                $lisresultsourcedidjson = $resourcelink->getSetting('lis_result_sourcedid');
                if ($lisresultsourcedidjson) {
                    $lisresultsourcedid = json_decode($lisresultsourcedidjson);
                    if (isset($lisresultsourcedid->data->typeid)) {
                        $toolcode = $lisresultsourcedid->data->typeid;
                    }
                }

                if ($toolcode) {
                    // Substitute fetched tool code value.
                    $membershipsurl = str_replace('{tool_code}', $toolcode, $membershipsurl);
                } else {
                    // We're unable to determine the tool code. End this processing.
                    return false;
                }
            }

            // Get context_id parameter and substitute, if applicable.
            $membershipsurl = str_replace('{context_id}', $context->getId(), $membershipsurl);

            // Get context_type and substitute, if applicable.
            if (strpos($membershipsurl, '{context_type}') !== false) {
                $contexttype = $context->type !== null ? $context->type : 'CourseSection';
                $membershipsurl = str_replace('{context_type}', $contexttype, $membershipsurl);
            }

            // Save this URL for the context's custom_context_memberships_url setting.
            $context->setSetting('custom_context_memberships_url', $membershipsurl);
            $contextupdated = true;
        }

        // Perform membership service request.
        $url = $context->getSetting('custom_context_memberships_url');
        mtrace("Performing membership service request from context with URL {$url}.");
        $members = $context->getMembership();

        // Save the context if membership request succeeded and if it has been updated.
        if ($members && $contextupdated) {
            $context->save();
        }

        return $members;
    }