I am using a self hosted WCF service and I am getting a little strange behavior from my service:
I use an Implementation of IDispatchMessageInspector to keep track of the requests/responses processed by my service.
When I add my service by using "Add service reference dialog" everything works fine. AfterReceivedRequest and BeforeSendReply is fired.
When I create the binding/endpoint using code only the service works fine, but AfterReceivedRequest and BeforeSendReply is not fired.
I'd be very happy if someone could point me in the right direction.
Marco.
Edit: here is the Code of the client creation:
Public Shared Function Do_RM(ByVal RMParameter As roClsRMParameter) As ROD.RM.Services.RoClsRMResult
Dim StartAdresse As String
Dim myBinding As BasicHttpBinding
Dim oRes As ROD.RM.Services.RoClsRMResult = Nothing
myBinding = Create_Binding()
myBinding.OpenTimeout = New TimeSpan(0, 0, TimeOutInSekunden)
myBinding.SendTimeout = New TimeSpan(0, 0, TimeOutInSekunden)
StartAdresse = "http://MyServer:8731/BASIC"
Dim Address = New EndpointAddress(StartAdresse)
Dim Client = New ROD.RM.Services.RODIS_QS_RMClient(myBinding, Address)
Client.Endpoint.Contract = Create_ContractDescription()
Client.Open()
oRes = Client.DoRM(RMParameter.A_BEL,
RMParameter.A_POS,
RMParameter.AVO,
RMParameter.Qualitaet,
RMParameter.Fehlernummer,
RMParameter.Anlage,
RMParameter.ChargenNr,
RMParameter.EinzelRueckmeldung,
RMParameter.NurTest,
RMParameter.Standort)
Client.Close()
Return oRes
End Function
Private Shared Function Create_ContractDescription() As ContractDescription
Dim oContract As ContractDescription
oContract = ContractDescription.GetContract(GetType(ROD.RM.Services.IRODIS_QS_RM), GetType(ROD.RM.Services.RODIS_QS_RMClient))
Return oContract
End Function
Private Shared Function Create_Binding() As BasicHttpBinding
Dim oHttpBinding As BasicHttpBinding = New BasicHttpBinding()
oHttpBinding.Name = "BasicHttpBinding_IRODIS_QS_RM"
oHttpBinding.CloseTimeout = TimeSpan.FromMinutes(1)
oHttpBinding.OpenTimeout = TimeSpan.FromMinutes(1)
oHttpBinding.ReceiveTimeout = TimeSpan.FromMinutes(10)
oHttpBinding.SendTimeout = TimeSpan.FromMinutes(1)
oHttpBinding.BypassProxyOnLocal = False
oHttpBinding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard
oHttpBinding.MaxBufferPoolSize = 524288
oHttpBinding.MaxReceivedMessageSize = 65536
oHttpBinding.MessageEncoding = WSMessageEncoding.Text
oHttpBinding.TextEncoding = Encoding.UTF8
oHttpBinding.UseDefaultWebProxy = True
oHttpBinding.AllowCookies = False
oHttpBinding.ReaderQuotas.MaxDepth = 32
oHttpBinding.ReaderQuotas.MaxArrayLength = 16384
oHttpBinding.ReaderQuotas.MaxStringContentLength = 8192
oHttpBinding.ReaderQuotas.MaxBytesPerRead = 4096
oHttpBinding.ReaderQuotas.MaxNameTableCharCount = 16384
Return oHttpBinding
End Function
Here are the parts for the Inspector of the Service:
Imports System.ServiceModel.Description
Public Class roClsRMLogBehavior
Implements IEndpointBehavior
Public Sub ApplyDispatchBehavior(ByVal endpoint As _
System.ServiceModel.Description.ServiceEndpoint, ByVal _
endpointDispatcher As _
System.ServiceModel.Dispatcher.EndpointDispatcher) _
Implements System.ServiceModel.Description.IEndpointBehavior.ApplyDispatchBehavior
Dim oInspector As roClsRMLog
oInspector = New roClsRMLog
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(oInspector)
End Sub
End Class
In the app.Config:
<extensions>
<behaviorExtensions>
<add name="roClsRMLogBehavior" type="RODIS_QS_BUCHEN_SERVICE.roclsRMLogBehaviorExtensionElement, RODIS_QS_BUCHEN_SERVICE, Version=1.1.3.1,Culture=neutral,PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
Related
I have been trying without success to return data from a an internally developed WebApi. The API uses Post requests to return data the body of the request containing complex criteria. I have previously had success using a Post Request to write data via the API, but I seem to have hit a brick wall in my efforts to return data. Here is the method I have been using:
Public Async Function Request(ByVal client As HttpClient, ByVal content As String) As Task
Dim buffer = System.Text.Encoding.UTF8.GetBytes(content)
Dim byteContent = New ByteArrayContent(buffer)
byteContent.Headers.ContentType = New MediaTypeHeaderValue("application/json")
Dim response = Await client.PostAsync(client.BaseAddress, byteContent)
Dim result As String = response.Content.ReadAsStringAsync().Result
_result = result
End Function
For conveninence the results are stored in a class variable, which enables me to test the routine using MSTest. The function should return a JSON array however it doesn't even return an error, rather it just returns Nothing.
Here is the associated TestMethod:
<TestMethod()> Public Sub ShouldSuccessfullyInterrodateTheSpenHapi()
Dim da = New SPEN.ODSDataPackagerService
Dim crit As New HttpCriterion
Dim stopped As Boolean
Dim jsonString As String = Nothing
crit.StartTime = "2022-11-03T00:00:00"
crit.EndTime = "2022-11-03T00:30:00"
crit.Interval = "30m"
crit.TagAttribute = "InstrumentTag"
crit.TagFilter = "confidential"
crit.Delimiter = "~"
crit.ServerName = "SPRODA"
'Deserialize object to JSON
jsonString = da.GetCriteriaJson(crit)
Try
da.InitialiseSettings()
da.Request(da.Clients(0), jsonString)
Debug.Print(da.Result)
Assert.IsTrue(True)
Catch ex As Exception
Assert.IsTrue(False)
End Try
End Sub
What am I missing guys?
EDIT:
Ok some further experimentation with the following code, I am at least now getting an error:
Public Async Function GetVoltagesFromPI(ByVal client As HttpClient, ByVal content As String) As Task(Of PIItemList)
Dim piItems As PIItemList = New PIItemList
Dim buffer = System.Text.Encoding.UTF8.GetBytes(content)
Dim byteContent = New ByteArrayContent(buffer)
byteContent.Headers.ContentType = New MediaTypeHeaderValue("application/json")
Try
Dim response As New HttpResponseMessage
response = Await client.PostAsync(client.BaseAddress, byteContent)
If response.IsSuccessStatusCode Then
_result = New PIItemList
_result = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result)
End If
Catch ex As Exception
Throw
Finally
End Try
End Function
The function errors at:
response = Await client.PostAsync(client.BaseAddress, byteContent)
with:
System.NullReferenceException: 'Object variable or With block
But really I am no further forward with regards a solution as far as I can make out the code should work, but there is obviously smething flawed in the code implementation.
Kind Regards
Paul.
Finally... Managed to get things working, here is the bare bones working code. Would appreciate any additional input though:
''' <summary>
''' Request pi data via the specified http endpoint (baseaddress)
''' </summary>
''' <param name="client"></param>
''' <param name="content"></param>
Public Function GetVoltagesFromPI(ByVal client As HttpClient, ByVal content As String) As Task(Of PIItemList)
Dim requestMsg As New HttpRequestMessage(HttpMethod.Post, client.BaseAddress)
Dim response As HttpResponseMessage
Dim interim As Object
Try
requestMsg.Content = New StringContent(content, Text.UTF8Encoding.Default, "application/json")
response = client.SendAsync(requestMsg).Result
If (response.StatusCode = System.Net.HttpStatusCode.OK) Then
_resultSet = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result)
End If
Catch ex As Exception
Throw
Finally
End Try
End Function
So, cutting a long story short the section of my code that I am currently unable to figure out is designed to report the current IP settings of a given NIC, so I want it to essentially spit out the IP, Subnet and default Gateway that it is currently set to. I have a solution working but it only seems to play nice when the NIC is set to DHCP which is not good for my application.
Here is my current code:
Public Sub NetGet()
MainForm.NetLabelIP.Text = "IPv4 Address: "
MainForm.NetLabelIP.Text = "subnet Mask: "
MainForm.NetLabelIP.Text = "Default Gateway: "
MainForm.NetLabelCN.Text = "Computer Name: " + System.Net.Dns.GetHostName()
For Each ip In System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList
If ip.AddressFamily = Net.Sockets.AddressFamily.InterNetwork Then
'IPv4 Adress
MainForm.NetLabelIP.Text = "IPv4 Address: " + ip.ToString()
For Each adapter As Net.NetworkInformation.NetworkInterface In Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
If adapter.Name = MainForm.interfaceSelector.SelectedItem Then
For Each unicastIPAddressInformation As Net.NetworkInformation.UnicastIPAddressInformation In adapter.GetIPProperties().UnicastAddresses
If unicastIPAddressInformation.Address.AddressFamily = Net.Sockets.AddressFamily.InterNetwork Then
If ip.Equals(unicastIPAddressInformation.Address) Then
'Subnet Mask
MainForm.NetLabelSM.Text = "Subnet Mask: " + unicastIPAddressInformation.IPv4Mask.ToString()
Dim adapterProperties As Net.NetworkInformation.IPInterfaceProperties = adapter.GetIPProperties()
For Each gateway As Net.NetworkInformation.GatewayIPAddressInformation In adapterProperties.GatewayAddresses
'Default Gateway
MainForm.NetLabelDG.Text = "Default Gateway: " + gateway.Address.ToString()
Next
If unicastIPAddressInformation.PrefixOrigin = 3 Then
DHCP = True
MainForm.NetLabelDHCP.Text = "DHCP Enabled: TRUE"
Else
DHCP = False
MainForm.NetLabelDHCP.Text = "DHCP Enabled: FALSE"
End If
''DNS1
'if adapterproperties.dnsaddresses.count > 0 then
' label5.text = adapterproperties.dnsaddresses(0).tostring()
'end if
''DNS2
'if adapterproperties.dnsaddresses.count > 1 then
' label6.text = adapterproperties.dnsaddresses(1).tostring()
'end if
End If
End If
Next
End If
Next
End If
Next
End Sub
I'm assuming it's going to be something abhorrently daft in hindsight, however I feel it best to share my request with the community so that anyone else looking for a similar solution can find their answers here.
Thanks in advance, guys.
This NetInterfacesInfo class implements two static (shared) methods the return informations on the Network Interfaces of a Machine:
NetInterfacesInfo.GetNetworkInterfaces()
This method returns all the Network Interfaces that support IPV4 except the Loopback interface.
The informations are returned in a List(Of NetWorkInterfacesInfo), which exposes these properties:
ConnectionName: The name assigned to the connection (Local Area Network (LAN))
Description: The firendly name of the Interface
IPV4Addresses: A simplified list of each Ip Address as string, the associated NetMask and Default Gateway.
IpAddresses: A list ot the IP Addresses associated with the Network Interface.
DHCPSservers: A list of the DHCP Servers associated with the Network Interface.
DnsServers: A list of the DNS Servers associated with the Network Interface.
Gateways: A list of Gateways addresses associated with the Network Interface.
IsDHCPEnabled: Specifies whether the IP Address is provided by a DHCP server or is a Static Address.
MacAddress: The MAC address of the NIC
Status: The Interface is functional (Up) or not (Down)
InterfaceType: The type of the Interface. This value can be one of the many possible types of Interfaces: Wireless80211, Tunnel, FastEthernetFx etc.
The IPV4Addresses property return a simplified list of the IP Addresses associated with the Network Interface. These informations are contained in a IpV4AddressInfo class, which provides these properties:
IpAddress: String representation of the IP Address.
NetMask: String representation of the NetMask of the Ip Address.
DefaultGateway: String representation of the Default Gateway address.
IsDnsEligible: Specifies that the IP Address can appear in a DNS (is routable)
Sample usage:
Dim allNicsInfo = NetInterfacesInfo.GetNetworkInterfaces()
For Each nic As NetInterfacesInfo.NetWorkInterfacesInfo In allNicsInfo
Console.WriteLine($"Description: {nic.Description} Type: {nic.InterfaceType}")
Next
Dim Wireless = allNicsInfo.Where(Function(nic) nic.InterfaceType = NetworkInterfaceType.Wireless80211)
NetInterfacesInfo.IpV4AddressSimpleList
The simplified list of IP Addresses associated with a Network Interface can also be retrieved using this static (shared) method, providing the Name (actually, the Description property) of a Network Interface.
This method returns a List(Of IpV4AddressInfo), a simplified, string only version, of each IP Address (of the specified Network Interface), its NetMask and the associated Default Gateway.
Sample usage:
Dim nicInfo = NetInterfacesInfo.IpV4AddressSimpleList("Some NIC Name")
For Each ipV4Addr As NetInterfacesInfo.IpV4AddressInfo In nicInfo
Console.WriteLine(ipV4Addr.IpAddress)
Console.WriteLine(ipV4Addr.NetMask)
Console.WriteLine(ipV4Addr.DefaultGateway)
Next
Attach the main class to a ComboBox:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim allNicsInfo = NetInterfacesInfo.GetNetworkInterfaces()
ComboBox1.DisplayMember = "ConnectionName"
ComboBox1.DataSource = allNicsInfo
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
Dim cbo = DirectCast(sender, ComboBox)
If cbo.SelectedIndex = -1 Then Return
Dim nicInfo = DirectCast(cbo.SelectedItem, NetInterfacesInfo.NetWorkInterfacesInfo)
TextBox1.Text = String.Join(Environment.NewLine, nicInfo.IPV4Addresses.
Select(Function(nic) $"IP Address: {nic.IpAddress} NetMask: {nic.NetMask}"))
TextBox2.Text = nicInfo.IPV4Addresses.First().DefaultGateway
End Sub
Imports System.Linq
Imports System.Net
Imports System.Net.NetworkInformation
Imports System.Net.Sockets
Public Class NetInterfacesInfo
Public Shared Function GetNetworkInterfaces() As List(Of NetWorkInterfacesInfo)
Dim ifInfo As New List(Of NetWorkInterfacesInfo)()
ifInfo.AddRange(GetNetworInterfaces().
Where(Function(nic) nic.NetworkInterfaceType <> NetworkInterfaceType.Loopback AndAlso
nic.Supports(NetworkInterfaceComponent.IPv4)).
Select(Function(nic) New NetWorkInterfacesInfo() With {
.Description = nic.Description,
.ConnectionName = nic.Name,
.IsDHCPEnabled = nic.GetIPProperties().GetIPv4Properties().IsDhcpEnabled,
.DHCPSservers = nic.GetIPProperties().DhcpServerAddresses.ToList(),
.DnsServers = nic.GetIPProperties().DnsAddresses.ToList(),
.Gateways = nic.GetIPProperties().GatewayAddresses.Select(Function(ipa) ipa.Address).ToList(),
.InterfaceType = nic.NetworkInterfaceType,
.IpAddresses = nic.GetIPProperties().UnicastAddresses.Select(Function(ipa) ipa.Address).ToList(),
.MacAddress = nic.GetPhysicalAddress().GetAddressBytes().
Select(Function(b) b.ToString("X")).Aggregate(Function(s1, s2) s2 + ":" + s1),
.Status = nic.OperationalStatus,
.IPV4Addresses = GetIpV4AddressInfo(nic)
}))
Return ifInfo
End Function
Public Shared Function IpV4AddressSimpleList(nicName As String) As List(Of IpV4AddressInfo)
Dim nic = GetNetworInterfaceByName(nicName)
If nic Is Nothing Then Return Nothing
Return nic.GetIPProperties().UnicastAddresses.
Where(Function(ipa) ipa.Address.AddressFamily = AddressFamily.InterNetwork).
Select(Function(ipa) New IpV4AddressInfo() With {
.IpAddress = ipa.Address?.ToString(),
.NetMask = ipa.IPv4Mask?.ToString(),
.IsDnsEligible = ipa.IsDnsEligible,
.DefaultGateway = nic.GetIPProperties().GatewayAddresses.FirstOrDefault()?.Address?.ToString()
}).ToList()
End Function
Private Shared Function GetIpV4AddressInfo(nic As NetworkInterface) As List(Of IpV4AddressInfo)
Return nic.GetIPProperties().UnicastAddresses.
Where(Function(ipa) ipa.Address.AddressFamily = AddressFamily.InterNetwork).
Select(Function(ipa) New IpV4AddressInfo() With {
.IpAddress = ipa.Address?.ToString(),
.NetMask = ipa.IPv4Mask?.ToString(),
.IsDnsEligible = ipa.IsDnsEligible,
.DefaultGateway = nic.GetIPProperties().GatewayAddresses.FirstOrDefault()?.Address?.ToString()
}).ToList()
End Function
Private Shared Function GetNetworInterfaces() As NetworkInterface()
Return NetworkInterface.GetAllNetworkInterfaces()
End Function
Private Shared Function GetNetworInterfaceByName(nicName As String) As NetworkInterface
Return NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(Function(nic) nic.Name = nicName)
End Function
Public Class NetWorkInterfacesInfo
Public Property ConnectionName As String
Public Property Description As String
Public Property IPV4Addresses As List(Of IpV4AddressInfo)
Public Property IpAddresses As List(Of IPAddress)
Public Property DHCPSservers As List(Of IPAddress)
Public Property DnsServers As List(Of IPAddress)
Public Property Gateways As List(Of IPAddress)
Public Property IsDHCPEnabled As Boolean
Public Property MacAddress As String
Public Property Status As OperationalStatus
Public Property InterfaceType As NetworkInterfaceType
End Class
Public Class IpV4AddressInfo
Public Property IpAddress As String
Public Property NetMask As String
Public Property DefaultGateway As String
Public Property IsDnsEligible As Boolean
End Class
End Class
Public Class Geocode
Public Structure GeocodeResult
Public Latitude As String
Public Longitude As String
Public Result As String
End Structure
Public Shared Function GetGeocode(ByVal Address As String) As GeocodeResult
Dim strLat As String = ""
Dim strLon As String = ""
Dim strResult As String = ""
Dim oXmlDoc As Object
GetGeocode.Latitude = ""
GetGeocode.Longitude = ""
GetGeocode.Result = ""
Try
Dim baseURL As String = "https://maps.google.com/maps/api/geocode/xml?sensor=false&address=" & Address
baseURL = Replace(baseURL, " ", "+")
oXmlDoc = CreateObject("Microsoft.XMLDOM")
With oXmlDoc
.Async = False
If .Load(baseURL) And Not .selectSingleNode("GeocodeResponse/status") Is Nothing Then
GetGeocode.Result = .selectSingleNode("GeocodeResponse/status").Text
If Not .selectSingleNode("GeocodeResponse/result") Is Nothing Then
GetGeocode.Latitude = .selectSingleNode("//location/lat").Text
GetGeocode.Longitude = .selectSingleNode("//location/lng").Text
Return GetGeocode
End If
End If
End With
oXmlDoc = Nothing
Return GetGeocode
Exit Function
Catch ex As Exception
Throw (ex)
End Try
Return GetGeocode
End Function
End Class
Ok so this works fine in production, qa, and localhost until we moved it to an Azure VM. From the VM we can go use a browser to get to the https://maps.google.com/maps/api/geocode/xml?sensor=false&address= URL. but when another page calls the getgeocode function the results are always blank meaning the rest api call failed in some way.
I don't think its the domain key restrictions because a) im not using a key in this call and b) i set my google api key to any domain to test it.
EDIT: I have tried using another service with the same result. It works in dev and on local machines but not on the Azure VMs. What I do not understand is how the REST apis are accessible via the browser, but return nothing when called from code.
Any ideas?
Explicitly creating a web client and loading that into the xml document has fixed this issue for me.
Imports Microsoft.VisualBasic
Imports System.Xml
Imports System.Linq
Imports System.Xml.Linq
Imports System.Net
Imports System.IO
Public Class Geocode
Public Structure GeocodeResult
Public Latitude As String
Public Longitude As String
Public Result As String
End Structure
Public Shared Function GetGeocode(ByVal Address As String) As GeocodeResult
Dim oXmlDoc As Object
GetGeocode.Latitude = ""
GetGeocode.Longitude = ""
GetGeocode.Result = ""
Try
Dim baseURL As String = "https://maps.google.com/maps/api/geocode/xml?sensor=false&address=" & Address
baseURL = Replace(baseURL, " ", "+")
Using WC As New WebClient()
oXmlDoc = CreateObject("Microsoft.XMLDOM")
With oXmlDoc
.Async = False
If .Load(WC.DownloadData(baseURL)) And Not .selectSingleNode("GeocodeResponse/status") Is Nothing Then
GetGeocode.Result = .selectSingleNode("GeocodeResponse/status").Text
If Not .selectSingleNode("GeocodeResponse/result") Is Nothing Then
GetGeocode.Latitude = .selectSingleNode("//location/lat").Text
GetGeocode.Longitude = .selectSingleNode("//location/lng").Text
Return GetGeocode
End If
End If
End With
oXmlDoc = Nothing
End Using
Return GetGeocode
Exit Function
Catch ex As Exception
Throw (ex)
End Try
Return GetGeocode
End Function
End Class
I made a little console application to help me with remapping client certificates to my webserver. However, when I try to run the application it is giving me an error of:
Unhandled exception at 0x00920309 in CertMapping.exe: 0xC0000005: Access violation reading location 0x00000000.
It's a pretty basic console app:
Imports Microsoft.Web.Administration
Module Module1
Sub main(ByVal cmdArgs() As String)
Dim WebSite As String = Nothing
Dim UserName As String = Nothing
Dim Password As String = Nothing
Dim Base64EncodedCertData As String = Nothing
Dim switch As String, arg As String
For Each Str As String In cmdArgs
switch = Split(Str, ":").First
arg = Split(Str, ":").Last
Select Case switch
Case "/Web"
WebSite = arg
Case "/User"
UserName = arg
Case "/Pwd"
Password = arg
Case "/Cert"
If arg = "mySecretCode" Then
Base64EncodedCertData = "ServerCertGoesHere"
Else
Base64EncodedCertData = arg
End If
End Select
Next
Using serverManager As New ServerManager
Dim config As Configuration = serverManager.GetWebConfiguration(WebSite.ToString)
Dim iisClientCertificateMappingAuthenticationSection As ConfigurationSection = config.GetSection("system.webServer/security/authentication/iisClientCertificateMappingAuthentication")
iisClientCertificateMappingAuthenticationSection("enabled") = True
iisClientCertificateMappingAuthenticationSection("oneToOneCertificateMappingsEnabled") = True
Dim oneToOneMappingsCollection As ConfigurationElementCollection = iisClientCertificateMappingAuthenticationSection.GetCollection("oneToOneMappings")
Dim addElement As ConfigurationElement = oneToOneMappingsCollection.CreateElement("add")
addElement.SetMetadata("lockItem", True)
addElement("enabled") = True
addElement("userName") = UserName.ToString
addElement("password") = Password.ToString
addElement("certificate") = Base64EncodedCertData.ToString
oneToOneMappingsCollection.Add(addElement)
Dim accessSection As ConfigurationSection = config.GetSection("system.webServer/security/access", WebSite.ToString)
accessSection("sslFlags") = "Ssl, SslNegotiateCert"
serverManager.CommitChanges()
End Using
End Sub
End Module
I am trying to access http://localhost/tempservicehost/tempservice.svc and I am getting the following error:
Error Description: 'Resource does not
exist'
This may be because an invalid URI or
HTTP method was specified. Please see
the service help page for constructing
valid requests to the service.
The funny thing is that http://localhost/tempservicehost/tempservice.svc/help is working fine. Not only that, all my endpoints are working fine.
I am using IIS 7.5 (Win 2008 R2). Application developed using .NET 4.0
Post Updated (following is the code):
<ServiceContract()>
Public Interface ITestSvc
<OperationContract()>
<Description("")>
<WebInvoke(Bodystyle:=WebMessageBodyStyle.Bare,
Method:="POST",
UriTemplate:="GetCodes")>
Function GetCodes(ByVal oReq As ReqGetCodes) As RespGetCodes
End Interface
Public Class TestSvc
Implements ITestSvc
Public Function GetCodes(ByVal oReq As ReqGetCodes) As RespGetCodes Implements ITestSvc.GetCodes
Dim o As New RespGetCodes
Dim lstGetCodes = New List(Of ClassGetCodes) From {
New ClassGetCodes With {.App_Code = "a1", .SystemFlag = True},
New ClassGetCodes With {.App_Code = "a2", .SystemFlag = False},
New ClassGetCodes With {.App_Code = "a3", .SystemFlag = True},
New ClassGetCodes With {.App_Code = "a4", .SystemFlag = True},
New ClassGetCodes With {.App_Code = "a5", .SystemFlag = False}
}
o.GetCodesArray = lstGetCodes.ToArray
Return o
End Function
End Class
Public Class TestWebHttpBehavior
Inherits WebHttpBehavior
Protected Overrides Sub AddServerErrorHandlers(ByVal endpoint As System.ServiceModel.Description.ServiceEndpoint, ByVal endpointDispatcher As System.ServiceModel.Dispatcher.EndpointDispatcher)
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear()
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(New TestErrorHandler)
End Sub
End Class
Public Class TestWcfSvcHostFactory
Inherits ServiceHostFactory
Protected Overrides Function CreateServiceHost(ByVal serviceType As Type, ByVal baseAddresses As Uri()) As ServiceHost
Dim result As New WebServiceHost2(serviceType, True, baseAddresses)
Dim sEnableBasicAuth As String = System.Configuration.ConfigurationManager.AppSettings.Get("EnableBasicAuthentication")
If String.IsNullOrEmpty(sEnableBasicAuth) OrElse String.Compare(sEnableBasicAuth, "false", True) <> 0 Then
result.Interceptors.Add(New TestRequestInterceptor(System.Web.Security.Membership.Provider, "Personify Authentication"))
End If
result.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.None
Dim bahavior As New TestWebHttpBehavior With {.AutomaticFormatSelectionEnabled = True}
result.Description.Endpoints(0).Behaviors.Add(bahavior)
Return result
End Function
End Class
Public Class TestRequestInterceptor
Inherits RequestInterceptor
Private m_provider As MembershipProvider
Private m_realm As String
Public Sub New(ByVal provider As MembershipProvider, ByVal realm As String)
MyBase.New(False)
Me.m_provider = provider
Me.m_realm = realm
End Sub
Protected ReadOnly Property Realm() As String
Get
Return m_realm
End Get
End Property
Protected ReadOnly Property Provider() As MembershipProvider
Get
Return m_provider
End Get
End Property
Public Overrides Sub ProcessRequest(ByRef requestContext As RequestContext)
Dim credentials As String() = ExtractCredentials(requestContext.RequestMessage)
If credentials.Length > 0 AndAlso AuthenticateUser(credentials(0), credentials(1)) Then
InitializeSecurityContext(requestContext.RequestMessage, credentials(0))
Else
Dim reply As Message = Message.CreateMessage(MessageVersion.None, Nothing)
Dim responseProperty As New HttpResponseMessageProperty() With {.StatusCode = HttpStatusCode.Unauthorized}
responseProperty.Headers.Add("WWW-Authenticate", String.Format("Basic realm=""{0}""", Realm))
reply.Properties(HttpResponseMessageProperty.Name) = responseProperty
requestContext.Reply(reply)
requestContext = Nothing
End If
End Sub
Private Function AuthenticateUser(ByVal username As String, ByVal password As String) As Boolean
If Provider.ValidateUser(username, password) Then
Return True
End If
Return False
End Function
Private Function ExtractCredentials(ByVal requestMessage As Message) As String()
Dim request As HttpRequestMessageProperty = DirectCast(requestMessage.Properties(HttpRequestMessageProperty.Name), HttpRequestMessageProperty)
Dim authHeader As String = request.Headers("Authorization")
If authHeader IsNot Nothing AndAlso authHeader.StartsWith("Basic") Then
Dim encodedUserPass As String = authHeader.Substring(6).Trim()
Dim encoding__1 As Encoding = Encoding.GetEncoding("iso-8859-1")
Dim userPass As String = encoding__1.GetString(Convert.FromBase64String(encodedUserPass))
Dim separator As Integer = userPass.IndexOf(":"c)
Dim credentials As String() = New String(1) {}
credentials(0) = userPass.Substring(0, separator)
credentials(1) = userPass.Substring(separator + 1)
Return credentials
End If
Return New String() {}
End Function
Private Sub InitializeSecurityContext(ByVal request As Message, ByVal username As String)
Dim principal As New GenericPrincipal(New GenericIdentity(username), New String() {})
Dim policies As New List(Of IAuthorizationPolicy)()
policies.Add(New PrincipalAuthorizationPolicy(principal))
Dim securityContext As New ServiceSecurityContext(policies.AsReadOnly())
If request.Properties.Security IsNot Nothing Then
request.Properties.Security.ServiceSecurityContext = securityContext
Else
request.Properties.Security = New SecurityMessageProperty() With { _
.ServiceSecurityContext = securityContext _
}
End If
End Sub
Private Class PrincipalAuthorizationPolicy
Implements IAuthorizationPolicy
Private m_id As String = Guid.NewGuid().ToString()
Private user As IPrincipal
Public Sub New(ByVal user As IPrincipal)
Me.user = user
End Sub
Public ReadOnly Property Id As String Implements System.IdentityModel.Policy.IAuthorizationComponent.Id
Get
Return Me.m_id
End Get
End Property
Public Function Evaluate(ByVal evaluationContext As System.IdentityModel.Policy.EvaluationContext, ByRef state As Object) As Boolean Implements System.IdentityModel.Policy.IAuthorizationPolicy.Evaluate
evaluationContext.AddClaimSet(Me, New DefaultClaimSet(Claim.CreateNameClaim(user.Identity.Name)))
evaluationContext.Properties("Identities") = New List(Of IIdentity)(New IIdentity() {user.Identity})
evaluationContext.Properties("Principal") = user
Return True
End Function
Public ReadOnly Property Issuer As System.IdentityModel.Claims.ClaimSet Implements System.IdentityModel.Policy.IAuthorizationPolicy.Issuer
Get
Return ClaimSet.System
End Get
End Property
End Class
End Class
The config is here:
<system.serviceModel>
<services>
<service behaviorConfiguration="TestWcfServiceBehavior"
name="TestServiceLib.TestSvc">
<endpoint address="" binding="webHttpBinding" behaviorConfiguration="EPrestBehavior"
name="EPrest" contract="TestServiceLib.ITestSvc" />
<endpoint address="mex" binding="mexHttpBinding" name="EPmex"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="EPrestBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="TestWcfServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
I Had a similar issue,
I found that if i navigated to an actual resource it was fine.
for example
http://localhost/tempservicehost/tempservice.svc/test/
assuming you have the following method as well
[OperationContract]
[WebGet(UriTemplate = "/test/")]
public Test TestMethod()
{
return new Test("Hello world");
}
what has happened here is that the standard 404 error that is normally returned has not been rendered the way you are expecting it to. (usually you get a blue header and a line saying service end point or similar)
If you want to customise your errors there is a question Custom Error Handling message for Custom WebServiceHost
That explains how to pick up error codes on the way through and modify the return.