WCF Restful API with multiple parameter

996 views Asked by At

I am working on creating a WCF restful API in VB.Net and so far getting data from the MSSQL databbase with one parameter and saving data are currently working. Currently I am trying to create a service contract with multiple parameters (email and password) to authenticate user login. This keeps throwing the following error and I just can not figure out how to resolve this:

Error: Cannot obtain Metadata from localhost:12345/SMPCService.svc If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address. For help enabling metadata publishing, please refer to the MSDN documentation at go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange Error URI: localhost:12345/SMPCService.svc Metadata contains a reference that cannot be resolved: localhost:12345/SMPCService.svc'. The requested service, 'localhost:12345/SMPCService.svc' could not be activated. See the server's diagnostic trace logs for more information.HTTP GET Error URI: localhost:12345/SMPCService.svc There was an error downloading '/localhost:12345/SMPCService.svc'. The request failed with the error message:--

This is my service contract:

<OperationContract()>
<WebInvoke(Method:="GET", ResponseFormat:=WebMessageFormat.Json, BodyStyle:=WebMessageBodyStyle.Wrapped, UriTemplate:="ValidateLogin/{e}/{p}")>
Function ValidateLogin(ByVal sEmailAddress As String, ByVal sPassword As String) As List(Of CheckLogin)

And this is the ValidateLogin Function that is called:

Public Function ValidateLogin(ByVal sEmailAddress As String, ByVal sPassword As String) As List(Of CheckLogin) Implements ISMPCService.ValidateLogin
    Dim result As List(Of CheckLogin) = New List(Of CheckLogin)
    Dim uAction = New CheckLogin
    Dim pwd As String = ""
    Try
        ' Dimension Local Variables
        Dim uRecSnap As ADODB.Recordset

        ' Check For Open Connection
        If uDBase Is Nothing Then
            OpenConnection()
            bConnection = True
        End If

        ' Run Stored Procedure - Load Timesheet Record
        uCommand = New ADODB.Command
        With uCommand
            .ActiveConnection = uDBase
            .CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
            .CommandTimeout = 0
            .Parameters.Append(.CreateParameter("@EmailAddress", ADODB.DataTypeEnum.adVarChar, ADODB.ParameterDirectionEnum.adParamInput, 30, sEmailAddress))
            .CommandText = "API_WebUser_ValidateLogin"
            uRecSnap = .Execute
        End With

        ' Populate List
        Do Until uRecSnap.EOF
            pwd = If(IsDBNull(uRecSnap("UserPassword").Value), "", uRecSnap("UserPassword").Value)
            uRecSnap.MoveNext()
        Loop
        uRecSnap = Nothing

        If pwd <> "" Then
            If pwd.Substring(0, 4) = "$2y$" Then
                Mid(pwd, 3, 1) = "a"
            End If

            If BCrypt.Net.BCrypt.Verify(SHA512Hash(sPassword), pwd) Then
                uAction.WasSuccessful = "OK"
                uAction.StatusDescription = "User credentials match"
            Else
                uAction.WasSuccessful = "FAIL"
                uAction.StatusDescription = "Failed to authorize user"
            End If

        Else
            uAction.WasSuccessful = "FAIL"
            uAction.StatusDescription = "Failed to authorize user"
        End If

        result.Add(uAction)
    Catch ex As Exception
        ' Catch Error
        If Err.Number <> 0 Then
            Console.WriteLine(ex.Message)
        End If

    Finally
        ' CleanUp

        ' Close Database Connection
        If bConnection Then CloseConnection()

    End Try

    Return result
End Function

Finally, this is my Web.config:

<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <!--Disabled custom errors to allow display of detailed errors.-->
    <customErrors mode="Off"/>
    <compilation debug="true" strict="false" explicit="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" relaxedUrlToFileSystemMapping="true"/>
  </system.web>
  <system.serviceModel>
    <services>
      <!--Specify services the application hosts. 
      Name specifies the type that provides an implementation of a service contract.
      Behavior Configuration specifies the name of one of the behaviours found in the behaviours element and governs actions such as whether the service allows impersonation.-->
      <service name="SMPCWebService.SMPCService" behaviorConfiguration="SMPCWebService.SMPCServiceBehaviour">
        <!--Define the service endpoints.-->  
        <endpoint address="../SMPCService.svc" behaviorConfiguration="webBehaviour" binding="webHttpBinding" contract="SMPCWebService.ISMPCService" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
          <behavior name="SMPCWebService.SMPCServiceBehaviour">
            <!-- To avoid disclosing metadata information, set the values below to false 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>
      <!--Define the endpoint behaviour.-->
      <endpointBehaviors>
        <behavior name="webBehaviour">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <!-- Allowing Cross-Origin Resource Sharing (CORS) - The httpProtocol settings allow web services to be called from external domains using JavaScript-->
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
      </customHeaders>
    </httpProtocol>
    <modules runAllManagedModulesForAllRequests="true"/>
    <httpErrors errorMode="Detailed" />
    <validation validateIntegratedModeConfiguration="false"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

I have looked into many posts to find hints to this matter but I did not get anywhere.

Posts I have looked at:

Why do I get this WCF error when 'GET'ing?

Failed to add a service. Service metadata may not be accessible. Make sure your service is running and exposing metadata.`

How to send email address as parameter in wcf method

http://jeffbarnes.net/blog/post/2006/10/16/metadata-exchange-endpoint.aspx

1

There are 1 answers

0
Nayon On BEST ANSWER

After trying out different approaches, I have finally solved where I went wrong.

The parameter names for the functions need to named same as the parameters specified in the UriTemplate.

Original:

<OperationContract()>
<WebInvoke(Method:="GET", ResponseFormat:=WebMessageFormat.Json, BodyStyle:=WebMessageBodyStyle.Wrapped, UriTemplate:="ValidateLogin/{e}/{p}")>
Function ValidateLogin(ByVal sEmailAddress As String, ByVal sPassword As String) As List(Of CheckLogin)

Fix:

<OperationContract()>
<WebInvoke(Method:="GET", ResponseFormat:=WebMessageFormat.Json, BodyStyle:=WebMessageBodyStyle.Wrapped, UriTemplate:="ValidateLogin/{e}/{p}")>
Function ValidateLogin(ByVal e As String, ByVal p As String) As List(Of CheckLogin)