web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Microsoft Dynamics AX (Archived)

IIS hosted Web service using an AX wcf service: The Target principle name is incorrect

(0) ShareShare
ReportReport
Posted on by

I'm a bit new to IIS hosted wcf services and I'm having some problems I can't resolve.

I have a wcf web service hosted on ISS that makes a call to a custom AX service.

I have tested the AX service through a C# console app and it works perfectly. But when I use it with the wcf service is appears to fail.

Using the wcf test client to test my service I get an A call to SSPI failed exception with the inner exception being "The Target principle name is incorrect"

I have set the wcf service on IIS to use the business connector process. It is in fact the only user that appears to work. Before making this change I was getting a failed to login to Dynamics AX error.

I have also tried various setting with the config file to change the end point Identity setting both the user principal name and the service principal name but that either has no effect or the wcf test client throws an exception.
I have also created an C# console app to make a call to the wcf service on IIS, but it this case it returns nothing, not even an error message.

What configuration do I need to have for this to work?

*This post is locked for comments

I have the same question (0)
  • Martin Dráb Profile Picture
    237,801 Most Valuable Professional on at

    I don't understand the following statement:

    I have tested the AX service through a C# console app and it works perfectly. But when I use it with the wcf service is appears to fail.

    What did you test if not a WCF service? And if you tested something, how is the test related to the service? Maybe you don't realize that web services hosted on AOS are WCF services too...

    Your problem with logging into AX probably means that you didn't set up BC proxy correctly. Make sure you follow Install web services on IIS [AX 2012].

    Regarding the other error, try to look at this thread: ax2012R2 - IIS on different host from AOS – target principal name is incorrect.

  • Community Member Profile Picture
    on at

    Hi Martin,

    I tested the AX service independently and it responds properly in that it sends back the correct data based on the parameters provided.

    The AX service is unable to meet the data contract (WSDL) expected by the third party client. So I need another service written in a .Net language to bridge AX and the third party software.

    That second service is written in C# and is hosted on IIS. In my VS project, I have a service reference to the AX service to connect to AX. That WCF service data contract was create using svcUtil and the WSDL provided by the third party software.

    When I test the IIS hosted service, it responds to the request and returns a response. As such, the service works. The content of the response indicates that an exception was thrown when it attempted to use the AX service. There is where my problems begin.

    First exception was "Unable to login into Dynamics AX". This exception was resolved when I changed the user on the service in IIS to the BC proxy user. I start getting the second exception.

    The second exception was the SSPI exception, which I had to get into the inner exceptions to find the message: "The Target principle name is incorrect".

    This is the one I haven't been able to figure out.

    I'm testing on the development box, which has IIS, AX and SQL running on it. So it isn't because the services are running on domain accounts. In any case, I had already found the post you indicated and tried what was suggested in it.

    I didn't install the dev box. As far as I can see, the BC proxy account is setup properly.

    I haven't been able to find which setup (if any) is wrong and how to fix it.

    Thanks

  • Martin Dráb Profile Picture
    237,801 Most Valuable Professional on at

    Okay, so the AX service works fine and the problem is in the service created by yourself. Please show us code of your service.

  • Community Member Profile Picture
    on at

    I'm not certain which part of the code you want to see, but here's the method that is called by the service operation from my last round of testing:


    I ran this through the debugger and it does enter into this method runs to the point where it makes the call to the AX service (as noted in the comments) which throws the exception it then goes into the catch segment where it fills the response with the error message that is then display in the client.

    It is when this service attempts to use the AX service that the exception is thrown.

    Again, everything is hosted on the same box.

            public GetCreditLimitAndBalanceDetailsResponse GetCreditLimitAndBalanceDetails(GetCreditLimitAndBalanceDetailsRequest request)
            {
                GetCreditLimitAndBalanceDetailsResponse response = new GetCreditLimitAndBalanceDetailsResponse();
                AxCreditLimitService.DLMGetCreditLimitBalanceDetailsRequest axRequest = new AxCreditLimitService.DLMGetCreditLimitBalanceDetailsRequest();
                // AX service parameters.
                axRequest.request = new AxCreditLimitService.DLMCreditLimitAndBalanceRequest();
                axRequest.securitySOAPHeader = new AxCreditLimitService.DLMSecuritySOAPHeader();
    
                axRequest.securitySOAPHeader.userName = request.SecuritySOAPHeader.UserName;
                axRequest.securitySOAPHeader.password = request.SecuritySOAPHeader.Password;
                axRequest.securitySOAPHeader.AnyAttr = request.SecuritySOAPHeader.AnyAttr;
    
                axRequest.request.accLedger = request.request.AccLedger;
                axRequest.request.balanceOverdueAgingOption = request.request.BalanceOverdueAgingOption;
                axRequest.request.companyCode = request.request.CompanyCode;
                axRequest.request.orgCode = request.request.OrgCode;
                axRequest.request.overdueAgingPeriod = request.request.OverdueAgingPeriod;
    
    
                try
                {
                    // Create a client to AX service
                    AxCreditLimitService.AxCreditLimitServiceClient AxCreditLimitClient = new AxCreditLimitService.AxCreditLimitServiceClient();
                    AxCreditLimitService.CallContext callContext = new AxCreditLimitService.CallContext();
                    // Call context added for testing had no effect, no longer used.
                    callContext.LogonAsUser = "{Hidden}";
    
                    // Call to AX service through the client throws exception
                    AxCreditLimitService.DLMGetCreditLimitBalanceDetailsResponse axResponse = AxCreditLimitClient.GetCreditLimitAndBalanceDetails(null, axRequest);
                    response.GetCreditLimitAndBalanceDetailsResult = new CreditLimitAndBalanceResponse();
    
                    response.GetCreditLimitAndBalanceDetailsResult.Succeeded = axResponse.GetCreditLimitAndBalanceDetailsResult.succeeded;
                    response.GetCreditLimitAndBalanceDetailsResult.ErrorMessage = axResponse.GetCreditLimitAndBalanceDetailsResult.errorMessage;
    
                    if (axResponse.GetCreditLimitAndBalanceDetailsResult.succeeded)
                    {
                        List<CreditLimitAndBalanceInfo> responseDetails = new List<CreditLimitAndBalanceInfo>();
                        foreach (AxCreditLimitService.DLMCreditLimitAndBalanceInfo axResponseDetail in axResponse.GetCreditLimitAndBalanceDetailsResult.creditLimitAndBalanceDetails)
                        {
                            CreditLimitAndBalanceInfo responseDetail = new CreditLimitAndBalanceInfo();
    
                            responseDetail.AccLedger = axResponseDetail.accLedger;
                            responseDetail.AccountBalanceNotOverdue = axResponseDetail.accountBalanceNotOverdueField;
                            responseDetail.AccountBalanceNotOverdueHasValue = axResponseDetail.accountBalanceNotOverdueHasValue;
                            responseDetail.AccountBalanceOverdueLessThanOnePeriod = axResponseDetail.accountBalanceOverdueLessThanOnePeriod;
                            responseDetail.AccountBalanceOverdueLessThanOnePeriodHasValue = axResponseDetail.acctBalanceDueLessThanOnePeriodHasValue;
                            responseDetail.AccountBalanceOverdueOnePeriodAndOver = axResponseDetail.accountBalanceOverdueOnePeriodAndOver;
                            responseDetail.AccountBalanceOverdueOnePeriodAndOverHasValue = axResponseDetail.acctBalanceDueOnePeriodAndOverHasValue;
                            responseDetail.AccountBalanceOverdueTwoPeriodsAndOver = axResponseDetail.accountBalanceOverdueTwoPeriodsAndOver;
                            responseDetail.AccountBalanceOverdueTwoPeriodsAndOverHasValue = axResponseDetail.acctBalanceDueTwoPeriodsAndOverHasValue;
                            responseDetail.AccountBalanceOverdueThreePeriodsAndOver = axResponseDetail.accountBalanceOverdueThreePeriodsAndOver;
                            responseDetail.AccountBalanceOverdueThreePeriodsAndOverHasValue = axResponseDetail.acctBalanceDueThreePeriodsOverHasValue;
                            responseDetail.AccountBalanceTotal = axResponseDetail.accountBalanceTotal;
                            responseDetail.AccountBalanceTotalHasValue = axResponseDetail.accountBalanceTotalHasValue;
                            responseDetail.BalanceOverdueAgingOption = axResponseDetail.balanceOverdueAgingOption;
                            responseDetail.CompanyCode = axResponseDetail.companyCode;
                            responseDetail.CreditLimit = axResponseDetail.creditLimit;
                            responseDetail.CreditLimitHasValue = axResponseDetail.creditLimitHasValue;
                            responseDetail.CurrencyCode = axResponseDetail.currencyCode;
                            responseDetail.ExternalCreditorCode = axResponseDetail.externalCreditorCode;
                            responseDetail.ExternalDebtorCode = axResponseDetail.externalDebtorCode;
                            responseDetail.IsOverCreditLimit = axResponseDetail.isOverCreditLimit;
                            responseDetail.IsOverCreditLimitHasValue = axResponseDetail.isOverCreditLimitHasValue;
                            responseDetail.IsOverCreditTerms = axResponseDetail.isOverCreditTerms;
                            responseDetail.IsOverCreditTermsHasValue = axResponseDetail.isOverCreditTermsHasValue;
                            responseDetail.LegacySystemCode = axResponseDetail.legacySystemCode;
                            responseDetail.OnCreditHold = axResponseDetail.onCreditHold;
                            responseDetail.OnCreditHoldHasValue = axResponseDetail.onCreditHoldHasValue;
                            responseDetail.OrgCode = axResponseDetail.orgCode;
                            responseDetail.OverdueAgingPeriod = axResponseDetail.overdueAgingPeriod;
                            responseDetail.OverdueTotal = axResponseDetail.overdueTotal;
                            responseDetail.OverdueTotalHasValue = axResponseDetail.overdueTotalHasValue;
                            responseDetail.SettlementGroupExternalCreditorCode = axResponseDetail.settlementGroupExternalCreditorCode;
                            responseDetail.SettlementGroupExternalDebtorCode = axResponseDetail.settlementGroupExternalDebtorCode;
                            responseDetail.SettlementGroupLegacySystemCode = axResponseDetail.settlementGroupLegacySystemCode;
                            responseDetail.SettlementGroupOrgCode = axResponseDetail.settlementGroupOrgCode;
                            responseDetail.UnpostedRevenueRecognisedTotal = axResponseDetail.unpostedRevenueRecognisedTotal;
                            responseDetail.UnpostedRevenueRecognisedTotalHasValue = axResponseDetail.unpostedRevenueRecognisedTotalHasValue;
                            responseDetail.UnpostedRevenueUnrecognisedTotal = axResponseDetail.unpostedRevenueUnrecognisedTotal;
                            responseDetail.UnpostedRevenueUnrecognisedTotalHasValue = axResponseDetail.unpostedRevenueUnrecognisedTotalHasValue;
                            responseDetails.Add(responseDetail);
                        }
                        response.GetCreditLimitAndBalanceDetailsResult.CreditLimitAndBalanceDetails = responseDetails.ToArray();
                    }
                }
                catch (Exception e)
                {
                    // Catchs SSPI exception this adds the exception message to response
                    response.GetCreditLimitAndBalanceDetailsResult = new CreditLimitAndBalanceResponse();
                    response.GetCreditLimitAndBalanceDetailsResult.Succeeded = false;
                    response.GetCreditLimitAndBalanceDetailsResult.ErrorMessage = "An exception has occured: " + e.InnerException.InnerException.Message;
    
                    List<CreditLimitAndBalanceInfo> responseDetails = new List<CreditLimitAndBalanceInfo>();
                    CreditLimitAndBalanceInfo responseDetail = new CreditLimitAndBalanceInfo();
    
                    responseDetails.Add(responseDetail);
    
                    response.GetCreditLimitAndBalanceDetailsResult.CreditLimitAndBalanceDetails = responseDetails.ToArray();
                }
    
                return response; // returns response to client
            }
    


    And here is the web.config for the service:

    <?xml version="1.0"?>
    <configuration>
    
      <system.web>
        <compilation debug="true" targetFramework="4.0" />
      </system.web>
      <system.serviceModel>
        <bindings>
          <netTcpBinding>
            <binding name="NetTcpBinding_AxCreditLimitService" closeTimeout="00:01:00" />
          </netTcpBinding>
          <basicHttpBinding>
            <binding name="CreditLimitServiceSoap" />
          </basicHttpBinding>
          <customBinding>
            <binding name="CreditLimitServiceSoap12" closeTimeout="00:02:00">
              <textMessageEncoding messageVersion="Soap12" />
            </binding>
          </customBinding>
        </bindings>
        <diagnostics>
          <messageLogging logEntireMessage="true" />
          <endToEndTracing activityTracing="true" />
        </diagnostics>
        <services>
          <service name="DLMCreditLimitService.CreditLimitService">
            <endpoint address="localhost/.../CreditLimitService.svc"
                binding="basicHttpBinding" bindingConfiguration="" name="CreditLimitServiceSoap"
                contract="CreditLimitServiceSoap">
              <identity>
                <userPrincipalName value="{Hidden: BC Proxy user}" /> <!-- Does not appear to have any effect -->
                <servicePrincipalName value="{Hidden: AOS user}"/> <!-- Does not appear to have any effect -->
              </identity>
            </endpoint>
          </service>
          </services>
        <client>
          <endpoint address="net.tcp://localhost:8201/DynamicsAx/Services/DLMCreditLimitServiceGroup"
            binding="netTcpBinding" bindingConfiguration="NetTcpBinding_AxCreditLimitService"
            contract="AxCreditLimitService.AxCreditLimitService" name="NetTcpBinding_AxCreditLimitService">
            <identity>
              <userPrincipalName value="{Hidden: BC Proxy user}" /> <!-- Required does not log into AX otherwise -->
              <servicePrincipalName value="{Hidden: AOS user}"/>
            </identity>
          </endpoint>
        </client>
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
              <serviceMetadata httpGetEnabled="true"/>
              <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
              <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    <!--    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> -->
      </system.serviceModel>
     <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
      </system.webServer>
      
    </configuration>
    
  • Martin Dráb Profile Picture
    237,801 Most Valuable Professional on at

    I see that you're not disposing your service clients. To be sure that that's not the cause, please fix your code and restart the AOS.

    By the way, you'll make your code much simpler and more readable if you don't always use fully qualified names. It's not needed. For example, instead of

    AxCreditLimitService.CallContext callContext = new AxCreditLimitService.CallContext();

    you can simply write

    CallContext callContext = new CallContext();

    You just have to add an extra using statement:

    using AxCreditLimitService;
  • Martin Dráb Profile Picture
    237,801 Most Valuable Professional on at

    The suspicious part of your code is where you change request headers. Can you remove it for testing purposes?

    And use CallContext when calling the message. You create a context but you never use it for anything.

  • Community Member Profile Picture
    on at

    I did the changes you suggested (and restarted the AOS) and it had no effect.

    The CallContext was a test which had no effect. Using it or using the default (by using null in the call) gives the same result.

    By the request headers do you mean:

               axRequest.request = new AxCreditLimitService.DLMCreditLimitAndBalanceRequest();

               axRequest.securitySOAPHeader = new AxCreditLimitService.DLMSecuritySOAPHeader();

               axRequest.securitySOAPHeader.userName = request.SecuritySOAPHeader.UserName;

               axRequest.securitySOAPHeader.password = request.SecuritySOAPHeader.Password;

               axRequest.securitySOAPHeader.AnyAttr = request.SecuritySOAPHeader.AnyAttr;

               axRequest.request.accLedger = request.request.AccLedger;

               axRequest.request.balanceOverdueAgingOption = request.request.BalanceOverdueAgingOption;

               axRequest.request.companyCode = request.request.CompanyCode;

               axRequest.request.orgCode = request.request.OrgCode;

               axRequest.request.overdueAgingPeriod = request.request.OverdueAgingPeriod;

    I need to do that because the data types from the IIS hosted service and the AX service are different. I'm simply creating the AX data types and initializing them with the information from the original request. This is needed for the AX service to process the request.

    This service is basically a client to the AX service. The third party software is the client for this service.

  • Community Member Profile Picture
    on at

    An update from my testing.

    The web service isn't the cause as such.

    I have been playing around with the wcf configuration of the AX service and I was able to reproduce the same exception with my AX service test console.

    When the service is in it's default setup the userPrincipaleName of the endpoint defaults to the AOS user. And in that default setup it works fine.

    When I change the end point to the BC proxy user, I get the exception:

    A call to SSPI failed, see inner exception

    Inner exception: A call to SSPI failed, see inner exception

    Final inner exception: The target principal name is incorrect

    The AX service will essentially not work with the BC proxy user, but works fine with the AOS user.

    Other course, the web service on IIS only works with the BC proxy user. All other users fails to log into AX.

    So how do I get the AX service to work with the BC Proxy user?

  • Martin Dráb Profile Picture
    237,801 Most Valuable Professional on at

    You're claiming that you're changing security SOAP headers "because the data types ... are different". It doesn't make sense to me. You're free to change data, what I asked you was not to meddle with authentication if you know that you have a problem with it. If you use the service as usual (without playing with headers), it still may not work, but it will become a simpler problem and you'll get into something which is supported.

    Regarding BC proxy, it's not a user. It's used to impersonate real AX users (which must have permissions to call the service).

  • Community Member Profile Picture
    on at

    If I try to pass the SOAP header from the WCF request to the AX service request, the code doesn't compile because it can't implicitly cast the .Net data type to the X++ data type.

    As for the AX service, the SOAP header can be empty (even null) and the service still works. It's not even used. I've actually tested that.

    When I say "BC Proxy user" I mean the user that has been setup as the BC proxy in AX which is required for IIS web services to work.

    I haven't been able to determine if the user has the permissions to call the service. That's what I was looking for in my testing.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > 🔒一 Microsoft Dynamics AX (Archived)

#1
Martin Dráb Profile Picture

Martin Dráb 4 Most Valuable Professional

#1
Priya_K Profile Picture

Priya_K 4

#3
MyDynamicsNAV Profile Picture

MyDynamicsNAV 2

Last 30 days Overall leaderboard

Featured topics

Product updates

Dynamics 365 release plans