I have an Actor Service which uses WCF:
[assembly: WcfActorRemotingProvider(RemotingListener = RemotingListener.V2Listener, RemotingClient = RemotingClient.V2Client)]
namespace Player.Interfaces
{
/// <summary>
/// This interface defines the methods exposed by an actor.
/// Clients use this interface to interact with the actor that implements it.
/// </summary>
public interface IPlayer : IActor
{
Task<bool> JoinGameAsync(ActorId gameId, string playerName);
Task<bool> MakeMoveAsync(ActorId gameId, int x, int y);
}
}
Using Service Remoting V2, I can write client code and access the methods:
var player1 = ActorProxy.Create<IPlayer>(new ActorId("Player 1"), "fabric:/ActorWCFApplication");
How do I achieve the same using WcfActorRemotingClientFactory or WCF?
var wcfRemotingClient = new WcfActorRemotingClientFactory(WcfUtility.CreateTcpClientBinding(), null,
servicePartitionResolver: partitionResolver);
Any code snippet for WCF client code for Actor?
Related
someone has the same problem using this code in the new WINUI3 app (Visual Studio 2022) as explained https://learn.microsoft.com/en-us/windows/communitytoolkit/mvvm/ioc :
public sealed partial class App : Application
{
public App()
{
Services = ConfigureServices();
this.InitializeComponent();
}
/// <summary>
/// Gets the current <see cref="App"/> instance in use
/// </summary>
public new static App Current => (App)Application.Current;
/// <summary>
/// Gets the <see cref="IServiceProvider"/> instance to resolve application services.
/// </summary>
public IServiceProvider Services { get; }
/// <summary>
/// Configures the services for the application.
/// </summary>
private static IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
services.AddSingleton<IFilesService, FilesService>();
services.AddSingleton<ISettingsService, SettingsService>();
services.AddSingleton<IClipboardService, ClipboardService>();
services.AddSingleton<IShareService, ShareService>();
services.AddSingleton<IEmailService, EmailService>();
return services.BuildServiceProvider();
}
}
This is NUGET packages installed
and this is my error:
You need to install:
Microsoft.Extensions.DependencyInjection
instead of,
Microsoft.Extensions.DependencyInjection.Abstractions
Error: Does not contain a definition for 'CreateServiceRemotingListener' and no extension method 'CreateServiceRemotingListener' accepting a first argument of type could be found (are you missing a using directive or an assembly reference?)
Below are the steps which I followed,
Created an interface that implements IService.
`
using Microsoft.ServiceFabric.Services.Remoting;
using System.Threading.Tasks;
public interface IFileService: IService
{
Task<string> GetStringByName(string name);
}
`
Included following packages in stateful service named as FileService.
`
using System. Fabric;
using Microsoft.ServiceFabric.Data;
using Microsoft.ServiceFabric.Data.Collections;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;
`
Implemented IFileService interface in FileService.
`
internal sealed class FileService : StatefulService, IFileService
{
public FileService(StatefulServiceContext context)
: base(context)
{ }
public FileService(StatefulServiceContext context, IReliableStateManagerReplica stateManagerReplica) : base(context, stateManagerReplica)
{
}
public Task<string> GetStringByName(string name)
{
return Task.FromResult<string>(name);
}
/// <summary>
/// Optional override to create listeners (e.g., HTTP, Service Remoting, WCF, etc.) for this service replica to handle client or user requests.
/// </summary>
/// <remarks>
/// For more information on service communication, see https://aka.ms/servicefabricservicecommunication
/// </remarks>
/// <returns>A collection of listeners.</returns>
protected override IEnumerable<ServiceReplicaListener>
CreateServiceReplicaListeners()
{
return new[] { new ServiceReplicaListener(this.CreateServiceRemotingListener) };
}}
`
The ServiceRemotingExtensions class is located in Microsoft.ServiceFabric.Services.Remoting.Runtime namespace (that isn't included).
The important point to mention is that CreateServiceRemotingListener is deprecated. The recommended method to use is CreateServiceRemotingReplicaListeners.
Hope this helps.
UPDATE 2019/01/28
Here is the sample code:
using System.Collections.Generic;
using System.Fabric;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Remoting;
using Microsoft.ServiceFabric.Services.Remoting.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;
namespace JustService
{
public interface IRemotingService : IService
{
// Remoting methods
}
internal sealed class JustService : StatefulService, IRemotingService
{
public JustService(
StatefulServiceContext context)
: base(context)
{
}
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return this.CreateServiceRemotingReplicaListeners();
}
}
}
Please note that in order to use CreateServiceRemotingReplicaListeners extension method the service should implement an interface derived from IService.
I have a console app that I'm using for an azure webjob. I need to have a unique nhibernate session per azure webjob request. I'm using autofact to manage DI.
How can I get Per Request Lifetime instancing in azure webjobs? Inherently a console app doesn't have this. Do I need to change project types?
I've seen several answers on how to do something similar here and here. But they basically boil down to passing in a container as a parameter to functions. That's not really instance per request.
As far as I know, the webjob doesn't have the request. It just run programs as background processes on App Service Web Apps. It couldn't get the request.
In my opinion, the Per Request Lifetime instancing is used in web application like ASP.NET web forms and MVC applications not webjobs.
What do you mean of the request?
Normally, we will use the Instance Per Dependency in the webjobs by using AutofacJobActivator.
It will auto create new instance when the function is triggered.
Here is a webjob example:
class Program
{
// Please set the following connection strings in app.config for this WebJob to run:
// AzureWebJobsDashboard and AzureWebJobsStorage
static void Main()
{
var builder = new ContainerBuilder();
builder.Register(c =>
{
var model = new DeltaResponse();
return model;
})
.As<IDropboxApi>()
.SingleInstance();
builder.RegisterType<Functions>().InstancePerDependency();
var Container = builder.Build();
var config = new JobHostConfiguration()
{
JobActivator = new AutofacJobActivator(Container)
};
var host = new JobHost(config);
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
}
public class AutofacJobActivator : IJobActivator
{
private readonly IContainer _container;
public AutofacJobActivator(IContainer container)
{
_container = container;
}
public T CreateInstance<T>()
{
return _container.Resolve<T>();
}
}
public interface IDropboxApi
{
void GetDelta();
}
public class DeltaResponse : IDropboxApi
{
public Guid id { get; set; }
public DeltaResponse()
{
id = Guid.NewGuid();
}
void IDropboxApi.GetDelta()
{
Console.WriteLine(id);
//throw new NotImplementedException();
}
}
Functions.cs:
public class Functions
{
// This function will get triggered/executed when a new message is written
// on an Azure Queue called queue.
private readonly IDropboxApi _dropboxApi;
public Functions(IDropboxApi dropboxApi)
{
_dropboxApi = dropboxApi;
}
public void ProcessQueueMessage([QueueTrigger("queue")] string message, TextWriter log)
{
log.WriteLine("started");
// Define request parameters.
_dropboxApi.GetDelta();
}
}
When the function triggered, it will auto create new instance.
I've a WCF service defined inside a library and a windows service which self-host this WCF service. I use Entity Framework 6 for Data Layer inside same library.
Who could confirm where I should defined connection string needed for EF?
Inside app.config of my self-hosting Windows Service? ie WindowsService.exe.config...
I want that this connection string would be available for all my WCF clients...
Thanks for your comments!
Ok, finally my issue was not related at all to app.config(s).
I didn't call correctly my WCF service.
To avoid proxies generation/use, I use ChannelFactory() in my WCF Service because I manage both servers and clients. This WCF Service is implemented throw MVVM Light with following code:
ViewModelLocator.cs:
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
//Define data access (wcf service) for design mode
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IService, Design.DesignDataService>();
}
...
}
WcfServer class:
public class WcfServer : IDisposable
{
//Wcf connection
private ChannelFactory<IService> _wcfFactory = null;
/// <summary>
/// Gets the DataService proxy from MVVMLight SimpleIOC instance.
/// </summary>
public IService DataService
{
get
{
return SimpleIoc.Default.GetInstance<IService>()??null;
}
}
/// <summary>
/// Add a Wcf server for a customer, a url and a server name
/// </summary>
/// <param name="customerName"></param>
/// <param name="serverName"></param>
/// <param name="urlServer"></param>
/// <param name=""></param>
public WcfServer(string customerName, string serverName, string urlServer)
{
_customerName = customerName;
ServerName = serverName;
UrlServer = urlServer;
}
/// <summary>
/// Connect to wcf service
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if a null exception is thrown all over Connect method</exception>
/// <exception cref="ObjectDisposedException">Thrown if an object is disposed all over Connect method</exception>
/// <exception cref="System.ServiceModel.Security.MessageSecurityException">Thrown if authentication failes with username/password over ssl</exception>
/// <exception cref="CommunicationObjectFaultedException">Faulted Exception on exception from ChannelFactory==>CreateChannel</exception>
/// <exception cref="System.InvalidOperationException">Invalid Operation Exception</exception>
/// <exception cref="Exception">Other exception</exception>
/// <returns>Returns true if connected</returns>
public bool Connect()
{
try
{
...
EndpointAddress endpointAddress = new EndpointAddress(new Uri(UrlServer));
if (_wcfFactory == null)
{
_wcfFactory = new ChannelFactory<IService>(WCFSharedConfiguration.ConfigureBindingWithSimplehttps(), endpointAddress);
//Open ChannelFactory
_wcfFactory.Open();
//Define Faulted handler
_wcfFactory.Faulted += FactoryFaulted;
}
else
//Log + return
if (!ViewModelBase.IsInDesignModeStatic)
{
//If we are not in Design (means blend or VS IDE)
SimpleIoc.Default.Register<IService>(() => _wcfFactory.CreateChannel(), true);
}
}
catch (Exception ex)
{
//Log
throw;
}
return true;
}
/// <summary>
/// Disconnect current channel
/// </summary>
/// <exception cref="TimeoutException">Timeout</exception>
/// <exception cref="CommunicationObjectFaultedException">Faulted Exception on exception from ChannelFactory==>CreateChannel</exception>
/// <exception cref="Exception">Other exception</exception>
/// <returns>True if successfull</returns>
public bool Disconnect()
{
...
}
May it helps!
I implemented my repository pattern and unit of work in the following way:
How to create a simple data access layer
How to create unit of work
and I was asked if create multiple instance of my database (which is the unit of work) will cause memory leak? and what are the downside of such implementation? or is the implementation done right?
Thanks.
What you should worry about is the creation of the DbContext as this is expensive.
I typically use one DbContext per request instead of creating multiple DbContext instances everywhere.
I store it in the HttpContext object and dispose of it at the end of the request.
You can find more info on it here
Find below my modified implementation. (original was from the link above and used ObjectContext).
My context class
using System.Data.Entity;
using System.Data.Objects;
using System.Web;
using Fot.Admin.Models;
namespace Context
{
public static class ContextManager
{
internal const string DB = "MY_DB_CONTEXT";
/// <summary>
/// Get an instance that lives for the life time of the request per user and automatically disposes.
/// </summary>
/// <returns>Model</returns>
public static T AsSingleton<T>() where T : DbContext, new()
{
HttpContext.Current.Items[DB] = (T)HttpContext.Current.Items[DB] ?? new T();
return (T)HttpContext.Current.Items[DB];
}
}
}
My Context Module
using System;
using System.Data.Entity;
using System.Data.Objects;
using System.Web;
namespace Context
{
/// <summary>
/// Entity Module used to control an Entities DB Context over the lifetime of a request per user.
/// </summary>
public class ContextModule : IHttpModule
{
private const string DB = ContextManager.DB;
void context_EndRequest(object sender, EventArgs e)
{
Dispose();
}
#region IHttpModule Members
public void Dispose()
{
if(HttpContext.Current != null)
{
if (HttpContext.Current.Items[DB] != null)
{
var entitiesContext = (DbContext) HttpContext.Current.Items[DB];
entitiesContext.Dispose();
HttpContext.Current.Items.Remove(DB);
}
}
}
public void Init(HttpApplication context)
{
context.EndRequest += new EventHandler(context_EndRequest);
}
#endregion
}
}
In my web.config under <httpModules> i add this below.
<add name="ContextModule" type="Context.ContextModule" />
This ensures that the end_Request is called after every request so you can dispose the context properly.
When you need the DbContext usage is as below.
var Context = ContextManager.AsSingleton<MyDBContext>();