On May 4, 9:10 am, Craig Neuwirt <[email protected]> wrote:
> On May 3, 2012, at 1:59 PM, Diego Mijelshon wrote:
> > On May 3, 2:47 pm, Craig Neuwirt <[email protected]> wrote:
> >> On May 3, 2012, at 12:11 PM, Diego Mijelshon wrote:
> >>> I'm using the WCF Facility for the first time to host a couple
> >>> services, both in a console app (for easy debugging) and IIS (for
> >>> production). The services use a net.msmq endpoint.
>
> >>> This is how I'm hosting the service in the console app (simplified):
>
> >>>  using (var host = new DefaultServiceHostFactory()
> >>>                                  
> >>> .CreateServiceHost(typeof(MyService).AssemblyQualifiedName,
> >>> new Uri[0]))
> >>>      host.Open();
>
> >> You don't need to create hosts, the facility does it for you
>
> > OK, how do I do that? I've seen samples for web apps, but not for
> > Console.
>
> It's always the same for web app, consoles, services, ... How the host 
> factory is used varies
>
>         container
>             .Register(Component.For<UserRequestService>()
>                         .AsWcfService(new DefaultServiceModel().AddEndpoints(
>                                         WcfEndpoint.ForContract<IOperations>()
>                                                         .At("<Put your 
> endpoint url here")
>                         )

That is nice. I didn't even need the DefaultServiceModel bit, as I'm
configuring the endpoints in app.config.

> >>> And here's how it's registered:
> >>> container.Register(Component.For<UserRequestService>().LifestylePerWcfOpera
> >>>  tion())
> >>> What I'd like to do is to add the following behavior to all
> >>> operations:
>
> >>>  [OperationBehavior(TransactionScopeRequired = true,
> >>> TransactionAutoComplete = true)]
>
> >>> Here's what I tried:
>
> >>>  container.Register(Component.For<IOperationBehavior>()
> >>>                               .UsingFactoryMethod(x => new
> >>> OperationBehaviorAttribute
> >>>                                                              {
>
> >>> TransactionScopeRequired = true,
>
> >>> TransactionAutoComplete = true
> >>>                                                              }));
>
> >>> But that results in an exception:
>
> >>>  System.ArgumentException: The value could not be added to the
> >>> collection, as the collection already contains an item of the same
> >>> type: 'System.ServiceModel.OperationBehaviorAttribute'.
> >>>                                             This collection only
> >>> supports one instance of each type.
> >>>  Parameter name: item
> >>>     at
> >>> System.Collections.Generic.KeyedByTypeCollection`1.InsertItem(Int32
> >>> index, TItem item)
> >>>     at
> >>> Castle.Facilities.WcfIntegration.Internal.WcfUtils.AddBehaviors[T]
> >>> (IKernel kernel, WcfExtensionScope scope, KeyedByTypeCollection`1
> >>> behaviors, IWcfBurden burden, Predicate`1 predicate)
> >>>     at
> >>> Castle.Facilities.WcfIntegration.WcfEndpointExtensions.Install(ServiceEndpo
> >>>  int
> >>> endpoint, Boolean withContract, IKernel kernel, IWcfBurden burden)
> >>>     at
> >>> Castle.Facilities.WcfIntegration.ServiceHostExtensions.Castle.Facilities.Wc
> >>>  
> >>> fIntegration.IWcfExtensionVisitor.VisitEndpointExtension(IWcfEndpointExtens
> >>>  ion
> >>> extension)
> >>>     at
> >>> Castle.Facilities.WcfIntegration.ServiceHostExtensions.Install(ICollection`
> >>>  1
> >>> extensions, IWcfBurden burden)
> >>>     at
> >>> Castle.Facilities.WcfIntegration.AbstractServiceHostBuilder.ConfigureServic
> >>>  eHost(ServiceHost
> >>> serviceHost, IWcfServiceModel serviceModel, ComponentModel model)
> >>>     at
> >>> Castle.Facilities.WcfIntegration.AbstractServiceHostBuilder`1.Build(Compone
> >>>  ntModel
> >>> model, Uri[] baseAddresses)
> >>>     at
> >>> Castle.Facilities.WcfIntegration.WindsorServiceHostFactory`1.CreateServiceH
> >>>  ost(String
> >>> constructorString, Uri[] baseAddresses)
> >>>     at Program.Main()
>
> >>> Any ideas?
>
> >> The reason this might be happening is that the OperationBehavior may be a 
> >> default behavior that must be
> >> first removed if you want to modify it.
>
> > That sounds possible, but how do I do that?
>
> create an operationbehavior to do it
>
> public class MyOperationPolicy : IOperationBehavior
> {
>   public void ApplyClientBehavior(
>         OperationDescription operationDescription,
>         ClientOperation clientOperation
>   )
>   {
>       var opBehavior = 
> operationDescription.Behaviors.Find<OperationBehaviorAttribute>();
>       if (opBehavior != null)  
> operationDescription.Behaviors.Remove(opBehavior);
>        operationDescription.Behaviors.Add(your new behavior with tx set)
>   }
>
> public void ApplyDispatchBehavior(
>         OperationDescription operationDescription,
>         DispatchOperation dispatchOperation
>  )
>  {
>      do the same thing
>   }
>
> }
>
> and then register that behavior in container
>
> container.Register(Component.For<IOperationBehavior>().ImplementedBy< 
> MyOperationPolicy>()
>
> Again, not sure if this will do it, but the error is usually caused by this

That did it... but unfortunately, it does not behave transactionally
as expected. My guess it that those attributes are read by either the
facility or the framework itself before I remove and re-add the
attribute. I left it with the attributes for now.

> >>> Something else I'm interested in is adding basic exception logging to
> >>> all operations. I'm already using the Logging facility for other parts
> >>> of my project and it works well. Any pointers or samples?
> >>> (It's worth noting that, since this uses MSMQ, all the operations are
> >>> OneWay, and the messages are moved automatically to a retry queue on
> >>> failure by the binding, which is OK. That's why I need a way to know
> >>> what went wrong with a particular message)
>
> >> The facility has message logging support which gives you an idea it works,
>
> > OK... and how do I use that?
>
> Obtain the source code for the WCF Facility and you'll see a directory 
> Behaviors/Logging which shows you how
> messages can be logged

Took me a while to get it going, but I got the basics from the test
fixtures (created an ErrorHandler class that implements IErrorHandler,
had to add it BEFORE registering the service)

Thanks a lot!

  Diego

-- 
You received this message because you are subscribed to the Google Groups 
"Castle Project Users" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/castle-project-users?hl=en.

Reply via email to