Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6238625
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 24, 20262026-05-24T11:14:55+00:00 2026-05-24T11:14:55+00:00

Here at work we’re working with an OData WCF Service to create our new

  • 0

Here at work we’re working with an OData WCF Service to create our new API. To fully implement our API, we’ve started extending the service with custom functions that allow us to trigger specific functionality that can’t be exposed through the normal means of OData.

One example is switching a Workspace entity into advanced mode. This requires alot of checks and mingling with data, that we opted to move this to a seperate function. This is the complete code of our Api.svc service:

using System.Net;
using System.ServiceModel.Web;

namespace TenForce.Execution.Web
{
    using System;
    using System.Data.Services;
    using System.Data.Services.Common;
    using System.Security.Authentication;
    using System.ServiceModel;
    using System.Text;
    using Microsoft.Data.Services.Toolkit;
    using Api2;
    using Api2.Implementation.Security;
    using Api2.OData;

    /// <summary>
    /// <para>This class represents the entire OData WCF Service that handles incoming requests and processes the data needed
    /// for those requests. The class inherits from the <see cref="ODataService<T>">ODataService</see> class in the toolkit to
    /// implement the desired functionality.</para>
    /// </summary>
    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class Api : ODataService<Context>
    {
        #region Initialization & Authentication

        // This method is called only once to initialize service-wide policies.
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.UseVerboseErrors = true;
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
            Factory.SetImplementation(typeof(Api2.Implementation.Api));
        }

        /// <summary>
        /// <para>This function is called when a request needs to be processed by the OData API.</para>
        /// <para>This function will look at the headers that are supplied to the request and try to extract the relevant
        /// user credentials from these headers. Using those credentials, a login is attempted. If the login is successfull,
        /// the request is processed. If the login fails, an AuthenticationException is raised instead.</para>
        /// <para>The function will also add the required response headers to the service reply to indicate the success
        /// or failure of the Authentication attempt.</para>
        /// </summary>
        /// <param name="args">The arguments needed to process the incoming request.</param>
        /// <exception cref="AuthenticationException">Invalid username and/or password.</exception>
        protected override void OnStartProcessingRequest(ProcessRequestArgs args)
        {
#if DEBUG
            Authenticator.Authenticate("secretlogin", string.Empty, Authenticator.ConstructDatabaseId(args.RequestUri.ToString()));
#else
            bool authSuccess = Authenticate(args.OperationContext, args.RequestUri.ToString());
            args.OperationContext.ResponseHeaders.Add(@"TenForce-RAuth", authSuccess ? @"OK" : @"DENIED");
            if (!authSuccess) throw new AuthenticationException(@"Invalid username and/or password");
#endif
            base.OnStartProcessingRequest(args);
        }

        /// <summary>
        /// <para>Performs authentication based upon the data present in the custom headers supplied by the client.</para>
        /// </summary>
        /// <param name="context">The OperationContext for the request</param>
        /// <param name="url">The URL for the request</param>
        /// <returns>True if the Authentication succeeded; otherwise false.</returns>
        private static bool Authenticate(DataServiceOperationContext context, string url)
        {
            // Check if the header is present
            string header = context.RequestHeaders["TenForce-Auth"];
            if (string.IsNullOrEmpty(header)) return false;

            // Decode the header from the base64 encoding
            header = Encoding.UTF8.GetString(Convert.FromBase64String(header));

            // Split the header and try to authenticate.
            string[] components = header.Split('|');
            return (components.Length >= 2) && Authenticator.Authenticate(components[0], components[1], Authenticator.ConstructDatabaseId(url));
        }

        #endregion

        #region Service Methods

        /*
         * All functions that are defined in this block, are special Service Methods on our API Service that become
         * available on the web to be called by external parties. These functions do not belong in the REST specifications
         * and are therefore placed here as public functions.
         * 
         * Important to know is that these methods become case-sensitive in their signature as well as their parameters when
         * beeing called from the web. Therefore we need to properly document these functions here so the generated document
         * explains the correct usage of these functions.
         */

        /// <summary>
        /// <para>Switches the specified <see cref="Workspace">Workspace</see> into advanced mode, using the specified
        /// Usergroup as the working <see cref="Usergroup">Usergroup</see> for the Workspace.</para>
        /// <para>The method can be called using the following signature from the web:</para>
        /// <para>http://applicationurl/api.svc/SwitchWorkspaceToAdvancedMode?workspaceId=x&usergroupId=y</para>
        /// <para>Where x stands for the unique identifier of the <see cref="Workspace">Workspace</see> entity and y stands for the unique
        /// identifier of the <see cref="Usergroup">Usergroup</see> entity.</para>
        /// <para>This method can only be invoked by a HTTP GET operation and returns a server response 200 when properly executed.
        /// If the request fails, the server will respond with a BadRequest error code.</para>
        /// </summary>
        /// <param name="workspaceId">The unique <see cref="Workspace">Workspace</see> entity identifier.</param>
        /// <param name="usergroupId">The unique <see cref="Usergroup">Usergroup</see> entity identifier.</param>
        [WebGet]
        public void SwitchWorkspaceToAdvancedMode(int workspaceId, int usergroupId)
        {
            Api2.Objects.Workspace ws = Factory.CreateApi().Workspaces.Read(workspaceId);
            Api2.Objects.Usergroup ug = Factory.CreateApi().UserGroups.Read(usergroupId);
            if(!Factory.CreateApi().Workspaces.ConvertToAdvancedPrivilegeSetup(ws, ug))
                throw new WebFaultException(HttpStatusCode.BadRequest);
        }

        #endregion
    }
}

The code is a bit large, but basicly what this extra functions do is check the supplied headers for each request and authenticate against the application with the provided username and password to ensure only valid users can work with our OData service.

The problem currently exists in the new function we declared at the bottom. The API requires a usercontext to be set for executing the functionality. This is normally done through the Authenticator class.

With the debugger, I followed a request and checked if the Authenticator is beeing called and it is. However when the SwitchWorkspaceToAdvancedMode function is triggered, this context is lost and it appears as nobody ever logged in.

The function calls are like this:

  • Create a new Api.svc instance
  • Trigger the OnStartProcessingRequest
  • Trigger the Authenticate method Trigger the
  • SwitchWorkspaceToAdvancedMode method

But this last one receives an error from the API stating that no login occured and no user context has been set. This means that we set the current thread principal to the thread that logged in.

From the error messages, I’m concluding that the actuall request for the SwitchWorkspaceToAdvancedMode is running on a different thread, and therefor it seems that no login ever occured because this is done from a different thread.

Am I right in this assumption, and if so, can I prevent this or work around it?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-24T11:14:56+00:00Added an answer on May 24, 2026 at 11:14 am

    I’ve solved this issue by adding a new ServiceBehavior to the DataService:

    [ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession)]
    

    This solved the apparent threading issue I had

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Here at work, we are working on a newsletter system that our clients can
I've just started using WCF here at work and am trying to add a
Here at work we have developed a SOAP WCF API that can be reached
Here at work we are using Subversion and CruiseControl.NET and as our source control
We're having a bit of fun here at work. It all started with one
We have a couple of ASP.NET applications running here at work and our users
We use .NET here at work and our project is a little mixed, with
We are having another discussion here at work about using parametrized sql queries in
I've got a few controllers here at work that contain methods I can use
I tried this JavaScript but it doesn't work - here I need to change

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.