azure service fabric wcf endpoint address net.tcp instead of http - wcf

Trying to set up a stateful reliable service with wcf in service fabric, I have copied this sample code:
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new[] { new ServiceReplicaListener((context) =>
new WcfCommunicationListener<IService1>(
wcfServiceObject:this,
serviceContext:context,
endpointResourceName: "ServiceEndpoint",
listenerBinding: WcfUtility.CreateTcpListenerBinding()
)
)};
In ServiceManifest.xml I have declared the endpoint:
<Resources>
<Endpoints>
<Endpoint Name="ServiceEndpoint" Protocol="http" Port="8100" />
<Endpoint Name="ReplicatorEndpoint" />
</Endpoints>
</Resources>
But when I deploy to local cluster, and look at the node where the service is running in Service Fabric Explorer, the endpoint has this address:
net.tcp://localhost:8100/455d1c74-7734-449b-a567-47b749b3b822/88af6851-0285-4989-b0aa-c0cbe8c2d06a-131056235989980581
How do I get a http address?

On my team, we have been working with wcf in service fabric these days. Firstly, We tried to use WcfCommunicationListener form Microsoft.ServiceFabric.Services.Wcf but finally we decide to use our own implementation of ICommunicationListener in order to have a better control over the service host. We also use net.tcp as binding instead of http. We defined behaviors and endpoints programatically, not using app.config.
I am going to share our approach. Hope this can help you.
First step, the ICommunicationListener implementation:
public class ServiceHostCommunicationListener : ICommunicationListener
{
private string baseAddress;
public ServiceHost Host { get; set; }
public ServiceHostCommunicationListener(ServiceHost host, string baseAddress)
{
Host = host;
this.baseAddress = baseAddress;
}
public void Abort()
{
Host.Abort();
}
public async Task CloseAsync(CancellationToken cancellationToken)
{
try
{
await Task.Factory.FromAsync(Host.BeginClose(null, null), ar =>
{
Host.EndClose(ar);
});
}
catch (Exception)
{
Host.Abort();
}
}
public Task<string> OpenAsync(CancellationToken cancellationToken)
{
return Task.Factory.FromAsync(Host.BeginOpen(null, null), ar =>
{
Host.EndOpen(ar);
return baseAddress;
});
}
}
Second step, create instance of the listener inside CreateServiceInstanceListeners inside our Service Fabric Service. Here is where I created a service host instance, its endpoints and behaviours.
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
yield return new ServiceInstanceListener(context =>
{
return CreateListener(context);
});
}
private ICommunicationListener CreateListener(StatelessServiceContext context)
{
Uri baseUri = new Uri($"net.tcp://{configuration.Network.BaseAddress}");
ServiceHost serviceHost = new ServiceHost(new SampleService(), baseUri);
InitServiceDebugBehavior(serviceHost);
if (configuration.Network.MetadataAddress != null)
{
AddMetadataEndpoint(baseUri, serviceHost);
}
InitServerCertificate(serviceHost);
AddServiceEndpoint(serviceHost);
return new ServiceHostCommunicationListener(serviceHost, baseUri.AbsoluteUri);
}
private void InitServiceDebugBehavior(ServiceHost host)
{
var serviceDebug = host.Description.Behaviors.Find<ServiceDebugBehavior>();
if (serviceDebug == null)
{
serviceDebug = new ServiceDebugBehavior();
host.Description.Behaviors.Add(serviceDebug);
}
serviceDebug.IncludeExceptionDetailInFaults = configuration.ServiceBehavior.ServerDebug.IncludeExceptionDetailInFaults;
}
private void AddMetadataEndpoint(Uri baseUri, ServiceHost serviceHost)
{
ServiceMetadataBehavior smb = serviceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior();
serviceHost.Description.Behaviors.Add(smb);
}
serviceHost.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
configuration.Network.MetadataAddress
);
}
private void InitServerCertificate(ServiceHost host)
{
var serverCertificateConfig = configuration.ServiceBehavior.ServerCertificate;
host.Credentials.ServiceCertificate.SetCertificate(
serverCertificateConfig.Store,
StoreName.My,
serverCertificateConfig.FindType,
serverCertificateConfig.FindValue
);
}
private void AddServiceEndpoint(ServiceHost serviceHost)
{
var binding = new NetTcpBinding(SecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
serviceHost.AddServiceEndpoint(typeof(SampleService), binding, configuration.Network.ServiceAddress);
}
Here is the configuration file, in case you have any doubts about it. We storage it inside PackageRoot-Config folder.
{
"Network": {
"BaseAddress": "localhost:1020/SampleService/",
"ServiceAddress": "service",
"MetadataAddress": "mex"
},
"ServiceBehavior": {
"ServerCertificate": {
"Store": "LocalMachine",
"FindType": "FindBySubjectDistinguishedName",
"FindValue": "CN=mycert.deploy.com"
},
"ServerDebug": {
"IncludeExceptionDetailInFaults": true
}
}
}

The only thing i can think of is manually create the Http binding based in this example:
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
SendTimeout = TimeSpan.MaxValue,
ReceiveTimeout = TimeSpan.MaxValue,
OpenTimeout = TimeSpan.FromSeconds(5),
CloseTimeout = TimeSpan.FromSeconds(5),
MaxReceivedMessageSize = 1024 * 1024
};
binding.MaxBufferSize = (int)binding.MaxReceivedMessageSize;
binding.MaxBufferPoolSize = Environment.ProcessorCount * binding.MaxReceivedMessageSize;
return binding;
With that binding the address is http in service fabric explorer

Related

Microservices Not responding after subscribing to RabbitMQ fanout exchange

My .net core3.1 web application has say 4 microservices (MasterMS, PartyMS, ProductMS, PurchaseMS)
and uses Rabbitmq as message broker.
In one specific scenario, the MasterMS publishes an event (insert/update in Company table) to Rabbitmq exchange (xAlexa), from where it is fanned-out to the respective queues of all subscribing MSs (PartyMS, ProductMS).
PartyMS get the event from CompanyEventPartyMS queue and ProductMS gets it from CompanyEventProductMS queue. Thereby both Party and Product updates their respective Company table and everything is in Sync and perfect. Btw, PurchaseMS is not subscribing and so not bothered.
Now comes the real problem.. The subscribing MSs (Consumers) does not respond when their web page is requested. PartyMS and ProductMS webpages throws SocketException, while the non-subscriber PurchaseMS works fine. Now if i Comment out the line where PartyMS subscribes, it starts working again though it no longer gets the CompanyEvent and goes out-of-sync.
Any insights friends ?
SocketException: No connection could be made because the target machine actively refused it.
System.Net.Http.ConnectHelper.ConnectAsync(string host, int port, CancellationToken cancellationToken)
public void Publish<T>(T #event) where T : Event
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: "xAlexa", type: ExchangeType.Fanout);
var message = JsonConvert.SerializeObject(#event);
var body = Encoding.UTF8.GetBytes(message);
var eventName = #event.GetType().Name;
channel.BasicPublish(exchange: "xAlexa",
routingKey: eventName, //string.Empty,
basicProperties: null,
body: body);
}
}
StartBasicConsume
private void StartBasicConsume<T>() where T : Event
{
var factory = new ConnectionFactory()
{
HostName = "localhost",
DispatchConsumersAsync = true
};
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
var eventName = typeof(T).Name;
var msName = typeof(T).FullName;
string[] str = { };
str = msName.Split('.');
eventName += str[1];
channel.ExchangeDeclare(exchange: "xAlexa",
type: ExchangeType.Fanout);
channel.QueueDeclare(eventName, true, false, false, null); //channel.QueueDeclare().QueueName;
channel.QueueBind(queue: eventName,
exchange: "xAlexa",
routingKey: string.Empty);
var consumer = new AsyncEventingBasicConsumer(channel);
consumer.Received += Consumer_Received;
channel.BasicConsume(eventName, true, consumer);
Console.WriteLine("Consumer Started");
Console.ReadLine();
}
private async Task Consumer_Received(object sender, BasicDeliverEventArgs e)
{
var eventName = e.RoutingKey;
var body = e.Body.ToArray();
//var body = e.Body.Span;
var message = Encoding.UTF8.GetString(body);
//var message = Encoding.UTF8.GetString(e.Body);
Console.WriteLine(message);
try
{
await ProcessEvent(eventName, message).ConfigureAwait(false);
}
catch (Exception ex)
{
}
}
The call to ProductsMS Api from MVC app (here is where it fails if subscribed and works if not subscribed to CompanyEvent !)
public class ProductService:IProductService
{
private readonly HttpClient _apiCLient;
public ProductService(HttpClient apiCLient)
{
_apiCLient = apiCLient;
}
public async Task<List<Product>> GetProducts()
{
var uri = "https://localhost:5005/api/ProductApi";
List<Product> userList = new List<Product>();
HttpResponseMessage response = await _apiCLient.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var readTask = response.Content.ReadAsStringAsync().Result;
userList = JsonConvert.DeserializeObject<List<Product>>(readTask);
}
return userList;
}
}
Find ProductsMS Api Startup.cs below:
namespace Alexa.ProductMS.Api
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
var connectionString = Configuration["DbContextSettings:ConnectionString"];
var dbPassword = Configuration["DbContextSettings:DbPassword"];
var builder = new NpgsqlConnectionStringBuilder(connectionString)
{
Password = dbPassword
};
services.AddDbContext<ProductsDBContext>(opts => opts.UseNpgsql(builder.ConnectionString));
services.AddMediatR(typeof(Startup));
RegisterServices(services);
}
private void RegisterServices(IServiceCollection services)
{
DependencyContainer.RegisterServices(services);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
ConfigureEventBus(app); //WORKS IF COMMENTED; FAILS OTHERWISE <---
}
private void ConfigureEventBus(IApplicationBuilder app)
{
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
eventBus.Subscribe<CompanyEvent, CompanyEventHandler>();
eventBus.Subscribe<PartyEvent, PartyEventHandler>();
}
}
}
Also see the images:
RabbitMQ fanout exchange
RabbitMQ Queues
exchange
queues
Remove the last line Console.ReadLine(); of the method StartBasicConsume().
When we are using that line in the function it is waiting for any key press or any input.

Provide exceptions for wcf webhttpbinding

I have to change a binding for wcf webservices from tcpbinding to webhttpbinding with basic authentication and ssl.
Webservices are self hosted in a console application and in a windows service for production version. Some of local services are with named pipe binding, just if a service call another service.
All works perfectly but not the global error manager (a class that implement IErrorHandler interface)
Some of DAL or business methods throw an exception with a custom message and this message was correctly provide to client (unit test for a while). But since I change binding, exceptions caught in unit test are always a 500 error, internal server error and custom messages are not in exception object.
Server code :
// Création de l'URI
var baseAddress = new Uri($"https://localhost/blablabla/{typeof(TBusiness).Name}");
// Création du Host avec le type de la classe Business
var host = new ServiceHost(typeof(TBusiness), baseAddress);
// Liaison WebHttpBinding sécurité transport
var binding = new WebHttpBinding
{
MaxBufferSize = 2147483647,
MaxReceivedMessageSize = 2147483647,
Security = new WebHttpSecurity
{
Mode = WebHttpSecurityMode.Transport
},
};
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
// Permet de renvoyer du xml et du json
var webBehavior = new WebHttpBehavior
{
AutomaticFormatSelectionEnabled = true
};
var ep = host.AddServiceEndpoint(typeof(TContracts), binding, "");
ep.Behaviors.Add(webBehavior);
var sdb = host.Description.Behaviors.Find<ServiceDebugBehavior>();
sdb.HttpHelpPageEnabled = false;
// Activation https
var smb = new ServiceMetadataBehavior
{
HttpGetEnabled = false,
HttpsGetEnabled = true,
};
host.Description.Behaviors.Add(smb);
// Ajout de l'authentification
var customAuthenticationBehavior = new ServiceCredentials();
customAuthenticationBehavior.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
customAuthenticationBehavior.UserNameAuthentication.CustomUserNamePasswordValidator = new SessionAuthentication();
host.Description.Behaviors.Add(customAuthenticationBehavior);
// Démarrage du host
host.Open();
Business method that throw exception :
public TOUser GetUserByLogin(string login)
{
using (var service = new ServiceProviderNamedPipe<IBFSessionManager, BSSessionManager>())
{
// Récupération de la DALUsers
var dal = service.Channel.GetDALUsers(OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name);
var user = dal.GetUserByLogin(login);
if (user == null) throw new FaultException(Errors.DALUsers_Err001);
return BMToolsEntitiesToTO.UserToTOUser(user);
}
}
Error global manager :
public class GlobalErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
// Empèche la propagation de l'erreur
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
var msg = error.Message;
// Création de l'exception de retour
var newEx = new FaultException(msg);
var msgFault = newEx.CreateMessageFault();
fault = Message.CreateMessage(version, msgFault, newEx.Action);
}
}
Unit test :
public void GetUserByLoginWithUnknownLoginTest()
{
TOUser user = null;
using (var service = new ServiceProviderHTTP<IBFUsers, BSUsers>(_user))
{
try
{
user = service.Channel.GetUserByLogin("1234");
}
catch (Exception e)
{
// e.message always provide "Internal server error instead of custom message (Errors.DALUsers_Err001)
Assert.AreEqual(Errors.DALUsers_Err001, e.Message);
}
Assert.IsNull(user);
}
}
All unit tests that catch exception failed since I change binding.
Thank you for your help.
I doubt whether your service is running correctly. Do you bind the certificate to the default port 443 due to transport layer security (using HTTPS)? Please use the below statement to bind a certificate to the 443 port.
netsh http add sslcert ipport=0.0.0.0:443 certhash=c20ed305ea705cc4e36b317af6ce35dc03cfb83d appid={c9670020-5288-47ea-70b3-5a13da258012}
please refer to this link.
https://learn.microsoft.com/en-us/windows/win32/http/add-sslcert
Here is a relevant discussion.
How to disable credentials input for HTTPS call to my WCF hosted in windows service
Besides, I didn’t see you apply the GlobalErrorHandler to the self-hosted service. This is usually implemented by service endpoint behavior.
ServiceEndpoint se = sh.AddServiceEndpoint(typeof(IService),new WebHttpBinding(), "");
MyEndpointBehavior bhv = new MyEndpointBehavior();
se.EndpointBehaviors.Add(bhv);
I wrote an example, wish it is useful to you.
class Program
{
static void Main(string[] args)
{
//I have already bound a certificate to the 21011 port.
var baseAddress = new Uri($"https://localhost:21011");
var host = new ServiceHost(typeof(MyService), baseAddress);
var binding = new WebHttpBinding
{
MaxBufferSize = 2147483647,
MaxReceivedMessageSize = 2147483647,
Security = new WebHttpSecurity
{
Mode = WebHttpSecurityMode.Transport
},
};
//basic authentication use windows login account located on the server-side instead of the below configuration(UserNamePasswordValidationMode.Custom)
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
// Permet de renvoyer du xml et du json
var webBehavior = new WebHttpBehavior
{
AutomaticFormatSelectionEnabled=true
};
var ep = host.AddServiceEndpoint(typeof(IService), binding, "");
ep.Behaviors.Add(webBehavior);
MyEndpointBehavior bhv = new MyEndpointBehavior();
ep.EndpointBehaviors.Add(bhv);
var sdb = host.Description.Behaviors.Find<ServiceDebugBehavior>();
sdb.HttpHelpPageEnabled = false;
// Activation https
var smb = new ServiceMetadataBehavior
{
HttpGetEnabled = true,
HttpsGetEnabled = true,
};
host.Description.Behaviors.Add(smb);
// Ajout de l'authentification
//var customAuthenticationBehavior = new ServiceCredentials();
//customAuthenticationBehavior.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
//customAuthenticationBehavior.UserNameAuthentication.CustomUserNamePasswordValidator = new SessionAuthentication();
//host.Description.Behaviors.Add(customAuthenticationBehavior);
// Démarrage du host
host.Open();
Console.WriteLine("service is running....");
Console.ReadLine();
Console.WriteLine("Closing.....");
host.Close();
}
}
[ServiceContract(ConfigurationName = "isv")]
public interface IService
{
[OperationContract]
[WebGet]
string Delete(int value);
}
[ServiceBehavior(ConfigurationName = "sv")]
public class MyService : IService
{
public string Delete(int value)
{
if (value <= 0)
{
throw new ArgumentException("Parameter should be greater than 0");
}
return "Hello";
}
}
public class MyError
{
public string Details { get; set; }
public string Error { get; set; }
}
public class MyCustomErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
MyError myerror = new MyError()
{
Details = error.Message,
Error = "An error occured"
};
fault = Message.CreateMessage(version, "messsagefault", myerror);
}
}
public class MyEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
return;
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
MyCustomErrorHandler myCustomErrorHandler = new MyCustomErrorHandler();
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(myCustomErrorHandler);
}
public void Validate(ServiceEndpoint endpoint)
{
return;
}
}
Result.
Feel free to let me know if there is anything I can help with.
After several search, I saw that a lot of people have same problem.
Here is my solution :
On server side, always throw a WebFaultException like this with correct HTTP Status code :
throw new WebFaultException<string>(myStringMessage, HttpStatusCode.NotFound);
On client side (only for unit tests or MVC project), cast exception to call GetResponseStream on Response object to get custom message :
var err = (WebException)e;
using (Stream respStream = err.Response.GetResponseStream())
{
using (var reader = new StreamReader(respStream))
{
var serializer = new XmlSerializer(typeof(string));
var response = reader.ReadToEnd();
return response.Substring(response.IndexOf('>') + 1).Replace("</string>", "");
}
}
In ProvideFault method from IErrorHandler, I just add code to write errors in a file but not create a message with Message.CreateMessage method.
It works correctly but generate an EndPointNotFoundException after ProvideFault, in some other posts I saw that a ProtocolException could be thrown.
Thank you for your remarks.

WCF large size request data handling concurrently

I have a self hosted WCF service for handling HTTP POST request.
My WCF service method will handle 2 types of request (1. getting data, 2. Do some action with given data).
My scenario :
1. Started Action request with large amount of data. : during the starting of that action do some processing.
2. client reads some results.
3. sending the remaining data for the previous action.
I implemented this using 'TcpListener' it is working.
Problem:
when i try to implement this scenario using WCF, i have got the 'Bad request' during the first action request.
[ServiceContract]
public interface ITest
{
[OperationContract, WebInvoke(Method = "POST", UriTemplate = "{*pathname}")]
Stream GetResponse(string pathname, Stream requestBody);
}
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Exact, ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = false, IncludeExceptionDetailInFaults = true)]
class TestService : ITest
{
public Uri BaseUri { get; private set; }
public IPAddress Address { get; private set; }
public Int32 Port { get; private set; }
public bool IsStarted { get { return Host != null; } }
public ServiceHost Host { get; private set; }
public TestService()
{
}
public TestService(IPAddress ipAddress, int port)
{
if (ipAddress == null) { throw new ArgumentNullException("Address"); }
this.Address = ipAddress;
this.Port = port;
this.BaseUri = new Uri(string.Format("http://{0}:{1}", this.Address, this.Port));
}
public void Start()
{
if (IsStarted) { throw new InvalidOperationException("Service is already started."); }
Host = CreateServiceHost();
Host.Open();
}
public void Stop()
{
if (!IsStarted) { throw new InvalidOperationException("Service is already stopped."); }
Host.Close();
Host = null;
}
private ServiceHost CreateServiceHost()
{
ServiceHost host = new ServiceHost(typeof(TestService), this.BaseUri);
WebHttpBinding webhttpBinding = new WebHttpBinding();
webhttpBinding.MaxBufferPoolSize = int.MaxValue;
webhttpBinding.MaxBufferSize = int.MaxValue;
webhttpBinding.MaxReceivedMessageSize = int.MaxValue;
CustomBinding binding = new CustomBinding(webhttpBinding);
WebMessageEncodingBindingElement webEncoding = binding.Elements.Find<WebMessageEncodingBindingElement>();
webEncoding.ContentTypeMapper = new RawMapper();
host.AddServiceEndpoint(typeof(ITest), binding, new Uri(this.BaseUri.AbsoluteUri)).Behaviors.Add(new WebHttpBehavior());
return host;
}
public Stream GetResponse(string pathname, Stream requestBody)
{
Stream response=null;
/************** Process 'requestBody' **************/
//requestBody contains "MY_ACTION"
//{
// Find the start delimeter from response : START processing
// Find the end delimeter from response : STOP processing
//}
//requestBody contains "GET_MY_DATA"
//{
// Find data and send response
//}
return response;
}
}
public class RawMapper : WebContentTypeMapper
{
public override WebContentFormat GetMessageFormatForContentType(string contentType)
{
return WebContentFormat.Raw;
}
}
Any help/guidance would be great as I'm really stuck on this.

WCF data services custom basic authentication

I have an WCF Data Service in .NET and I am consuming this service with datajs in Phonegap. I am trying to implement authentication as decribed here: http://goo.gl/0xQvC, and sending credentials with OData.read method. When I read credentials in the service with HttpContext.Current.Request.Headers["Authorization"], I found they are empty. What I am doing wrong?
Service Code:
[ServiceBehavior( IncludeExceptionDetailInFaults = true )]
public class TeyunaDataService : DataService< Meteora.TeyunaServices.Models.TeyunaContext >
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Clientes", EntitySetRights.AllRead );
config.SetEntitySetAccessRule("Transacciones", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.UseVerboseErrors = true;
}
public TeyunaDataService()
{
this.ProcessingPipeline.ProcessingRequest += new EventHandler<DataServiceProcessingPipelineEventArgs>(OnRequest);
}
void OnRequest(object sender, DataServiceProcessingPipelineEventArgs e)
{
var auth = HttpContext.Current.Request.Headers["Authorization"]; //This is empty
}
}
}
Javascript Client code:
OData.read({ requestUri: url, user: "pruebausr", password: "passprb" },
function (data, request) {
// ... code to procesing data (It works fine)
}, function(err) {
$.mobile.hidePageLoadingMsg();
alert("Error al obtener clientes. " + err.message);
}
);
Service web.config here: https://gist.github.com/3746043
I am using:
WCF Data Services 5.
IIS Express.

The AutofacServiceHost.Container static property must be set before services can be instantiated

Within my XXXX.WS WCF services project I'm trying to get DI/IOC using autofac going...been at it all day but I think I'm close (different errors are progress here)...this error I can't understand how to shake..."AutofacServieHost.Container static property must be set..."..but I think I am setting it!?! What am I doing wrong?
protected void Application_Start(object sender, EventArgs e)
{
var builder = new ContainerBuilder();
builder.Register(c => new DatabaseFactory()).As<IDatabaseFactory>().Named<DatabaseFactory>("DBFactory");
builder.Register(c => new ListingSqlRepository(c.ResolveNamed<DatabaseFactory>("DBFactory"))).As<IListingSqlRepository>().Named<ListingSqlRepository>("LSR");
builder.Register(c => new ListingRepository(c.ResolveNamed<ListingSqlRepository>("LSR"))).As<IListingRepository>().Named<ListingRepository>("LR");
builder.Register(c => new Service1(c.ResolveNamed<IListingRepository>("LR"))).As<IService1>();
using (var container = builder.Build())
{
Uri address = new Uri("http://localhost:57924/Service1");
ServiceHost host = new ServiceHost(typeof(Service1), address);
host.AddServiceEndpoint(typeof(IService1), new BasicHttpBinding(), string.Empty);
host.AddDependencyInjectionBehavior<IService1>(container);
//BREAKS HERE?
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true, HttpGetUrl = address });
host.Open();
Console.WriteLine("The host has been opened.");
Console.ReadLine();
host.Close();
Environment.Exit(0);
}
}
Then the SERVICE:
namespace LOTW2012.WS
{
public class Service1 : IService1
{
private IListingRepository _listingRepository { get; set; }
public Service1(IListingRepository iLR) {
this._listingRepository = iLR;
}
public Service1()
{
}
public List<Listing> GetListingsByStateName(string stateName)
{
//todo ..getall for now
var listings = _listingRepository.GetAll().ToList();
return listings;
}
You need to tell the Autofac WCF integration about the container you build by setting the property in question:
var builder = new ContainerBuilder();
// ...
AutofacHostFactory.Container = builder.Build();
// ...
This will allow Autofac to resolve service types.