Ошибка несоответствия контракта WCF при использовании Autofac для регистрации конечной точки через ChannelFactory - PullRequest
2 голосов
/ 20 апреля 2011

У меня есть служба WCF, которая работает, когда к ней обращается простое приложение MVC.

Когда я пытаюсь сделать вызов на той же конечной точке из другого приложения MVC, которое связано с Autofac Я получаю исключение привязки / несоответствия контракта , например:

Тип содержимого application / soap + xml;charset = utf-8 не поддерживается службой http://localhost:6985/ProductService.svc. Возможно, не совпадают привязки клиента и службы.

System.Net.WebException: удаленный сервер возвратил ошибку: (415) Unsupported Media Type.

Я достаточно уверен, что у меня нет несоответствия в настройках конфигурации на обоих концах, я основываю эту уверенность на тестировании одинаковых настроек на комбинации WCF + MVC, где отсутствует Autofac,Настройки конфигурации находятся на pastebin.com / t7wfR77h .

Поэтому я хотел бы помочь с анализом, если вопрос о том, как я зарегистрировал зависимость / конечную точку в Autofac, является проблемой ...

* Код Application_Start * в приложении MVC для настройки Autofac:

var builder = new ContainerBuilder();
//other registrations...

builder.Register(c => 
            new ChannelFactory<IProductService>(
                new WSHttpBinding("ProductService_wsHttpBinding"),
                new EndpointAddress("http://localhost:6985/ProductService.svc")
            )
        ).SingleInstance();

builder.Register(c =>
        {
            var factory = c.Resolve<ChannelFactory<IProductService>>();
            return factory.CreateChannel();
        }
      ).InstancePerHttpRequest();

var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

(для полноты), где я использую его, находится в ProductController, который имеет только одну зависимость для внедрения, очень просто:

public class ProductController : AsyncController
{
    private IProductService _service;

    public ProductController(IProductService ps)
    {
        _service = ps;
    }

    //...
    //later simply call
    _service.SomeMethod();
}

1 Ответ

2 голосов
/ 12 октября 2011

Как уже упоминалось в комментарии к @Nick Josevski, мне удалось получить что-то похожее на работу.

В методе Application_Start моего приложения MVC3 у меня есть следующий код:

protected void Application_Start()
{
    var builder = new ContainerBuilder();
    builder.Register(c => new ChannelFactory<ICartService>("CartService")).SingleInstance();
    builder.Register(c => c.Resolve<ChannelFactory<ICartService>>().CreateChannel()).InstancePerHttpRequest();
    var container = builder.Build();
    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

    // other MVC startup activities, like registering areas and routes
}

Эти регистрации собирают данные конфигурации WCF из Web.config.Я также получил регистрацию для работы с конечными точками, определенными в коде.Для полноты вот некоторые подходящие записи Web.config на стороне клиента:

<system.serviceModel>
  <bindings>
    <basicHttpBinding>
      <binding name="BasicHttpBinding" ... />
    </basicHttpBinding>
  </bindings>
  <client>
    <endpoint address="http://localhost:50930/Purchasing/CartService.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding"
        contract="CartService.ICartService" name="CartService" />
  </client>
</system.serviceModel>

Затем в моем контроллере есть код, подобный следующему:

using Autofac.Features.OwnedInstances;

public class BulkCartController : Controller
{
    private readonly Owned<ICartService> cartService_;

    public BulkCartController(Owned<ICartService> cartService)
    {
        cartService_ = cartService;
    }

    protected override void Dispose(bool disposing) // defined in Controller
    {
        cartService_.Dispose();
        base.Dispose(disposing);
    }

    //
    // GET: /BulkCart/Get/1
    public ActionResult Get(int id)
    {
        var model = new ShoppingCart { ShoppingCartId = id };
        using (var cartService = cartService_)
        {
            model.Items = cartService.Value.GetCartProductItems(id);
        }
        return View("Get", model);
    }
}

выглядит модульное тестированиекак это:

using Autofac.Features.OwnedInstances;
using Autofac.Util;
using Moq;

[TestMethod]
public void Get_ReturnsItemsInTheGivenCart()
{
    var mock = new Mock<ICartService>(MockBehavior.Strict);
    mock.Setup(x => x.GetCartProductItems(2)).Returns(new CartProductItemViewObject[0]);
    var controller = new BulkCartController(new Owned<ICartService>(mock.Object, new Autofac.Util.Disposable())); 
    var result = controller.Get(2);

    Assert.IsInstanceOfType(result, typeof(ViewResult));
    var view = (ViewResult)result;
    Assert.AreEqual("Get", view.ViewName);

    Assert.IsInstanceOfType(view.ViewData.Model, typeof(ShoppingCart));
    var model = (ShoppingCart)view.ViewData.Model;
    Assert.AreEqual(2, model.ShoppingCartId);
    Assert.AreEqual(0, model.Items.Length);
}

Я проверяю удаление с помощью модульного теста, определенного в базовом классе теста абстрактного контроллера:

[TestClass]
public abstract class ControllerWithServiceTestBase<TController, TService>
    where TController : Controller
    where TService : class
{
    [TestMethod]
    public virtual void Dispose_DisposesTheService()
    {
        var disposable = new Mock<IDisposable>(MockBehavior.Strict);
        disposable.Setup(x => x.Dispose()).Verifiable();

        var controller = (TController) Activator.CreateInstance(typeof(TController), new Owned<TService>(null, disposable.Object));
        controller.Dispose();

        disposable.Verify();
    }
}

Одна вещь, которую я пока не знаю, - это использование этогоOwned<T> и Dispose() дают мне адекватную утилизацию, или мне нужно будет использовать LifetimeScope согласно Пожизненному учебнику для начинающих Autofac .

...