pmichna
pmichna

Reputation: 4888

How to implement WCF in my project?

I have a project that communicates with a SQLExpress DB via EntityFramework. Now I want to add a WCF layer to the system.

Here is some piece of code that I had in the first version (no WCF):

MessageService.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newsletter.DAL;
using System.Data.Entity;
using System.Windows;
using System.Data.Objects.DataClasses;

namespace Newsletter.Services
{
    public class MessageService
    {
        private NewsletterEntities _context;
    public MessageService()
    {
        _context = new NewsletterEntities();
    }
    public Task AddMessageAsync(string subject,string content, bool hasAttachments, DateTime date, Sender sender, MailingList mailingList)
    {
        return Task.Factory.StartNew(() =>
            {
                Message newMessage = new Message();
                newMessage.Subject = subject;
                newMessage.Content = content;
                newMessage.HasAttachments = hasAttachments;
                newMessage.Date = date;
                newMessage.Sender = sender;
                newMessage.MailingList = mailingList;
                _context.Messages.AddObject(newMessage);
                _context.SaveChanges();
            });
    }

    public Task EditMessageAsync(int id, DateTime date, string content, MailingList mailingLists, Sender sender, string subject, bool hasAttachments)
    {
        return Task.Factory.StartNew(() =>
            {
                var messageToChange = (from m in _context.Messages where id == m.MessageID select m).FirstOrDefault();
                if (messageToChange != null)
                {
                    messageToChange.Date = date;
                    messageToChange.Content = content;
                    messageToChange.MailingList = mailingLists;
                    messageToChange.Sender = sender;
                    messageToChange.Subject = subject;
                    messageToChange.HasAttachments = hasAttachments;
                    _context.SaveChanges();
                }
            });
    }

    public Task<List<Message>> GetAllMessagesAsync()
    {
        return Task.Factory.StartNew(() => _context.Messages.ToList());
    }

    public Task<List<MailingList>> GetAllMailingListsAsync()
    {
        return Task.Factory.StartNew(() => _context.MailingLists.ToList());
    }

    public Task<List<Sender>> GetAllSendersAsync()
    {
        return Task.Factory.StartNew(() => _context.Senders.ToList());
    }

    public Task DeleteMessageAsync(Message message)
    {
        return Task.Factory.StartNew(() =>
            {
                MailingList mailinglist = message.MailingList;
                mailinglist.Message.Remove(message);

                _context.Messages.DeleteObject(message);
                _context.SaveChanges();
            });
    }
}
}

I wanted to start with something simple to check whether I know in general what's going on. I created WCF Service Library project. There I have IMessageService.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Newsletter.Common;

namespace WcfServiceLibrary
{
    [ServiceContract]
    public interface IMessageService
    {
        [OperationContract]
        void DeleteMessage(MessageDTO message);
    }
}

and MessageService.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Newsletter.Common;
using Newsletter.DAL;
using System.Data.Entity;
using System.Data.Objects.DataClasses;

namespace WcfServiceLibrary
{
    public class MessageService : IMessageService
    {
        private NewsletterEntities _context;

        public MessageService()
        {
            _context = new NewsletterEntities();
        }

        public void DeleteMessage(MessageDTO messageDTO)
        {
            MailingList mailinglist = (from m in _context.MailingLists where m.MailingListID == messageDTO.MailingListID select m).FirstOrDefault();
            Message message = (from m in _context.Messages where m.MessageID == messageDTO.MessageID select m).FirstOrDefault();
            mailinglist.Message.Remove(message);

            _context.Messages.DeleteObject(message);
            _context.SaveChanges();
        }
    }
}

Finally MessageDTO.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Newsletter.Common
{
    public class MessageDTO
    {
        public int MessageID { get; set; }
        public String Subject { get; set; }
        public String Content { get; set; }
        public bool HasAttachments { get; set; }
        public DateTime Date { get; set; }
        public int SenderID { get; set; }
        public int MailingListID { get; set; }
    }
}

I marked it as a startup project and tried it out with WCF Test Client. I invoke the DeleteMessage() method with some object with MessageID = 1 and MailingList = 5 - those are the values of a particular record in my DB. Thats' the point when I get an error - unhandled exception from DAL:

The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid. and after stopping debugger:

An error occurred while receiving the HTTP response to http://localhost:8733/WcfServiceLibrary/MessageService/. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.

Server stack trace:     at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)    at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)    at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)    at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)    at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)    at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)    at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:     at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)    at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)    at IMessageService.DeleteMessage(MessageDTO message)    at MessageServiceClient.DeleteMessage(MessageDTO message)

Inner Exception: The underlying connection was closed: An unexpected error occurred on a receive.    at System.Net.HttpWebRequest.GetResponse()    at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)

Inner Exception: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.    at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)    at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size)    at System.Net.Connection.SyncRead(HttpWebRequest request, Boolean userRetrievedStream, Boolean probeRead)

Inner Exception: An existing connection was forcibly closed by the remote host    at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)    at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)

App.config of WCF:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <!-- When deploying the service library project, the content of the config file must be added to the host's 
  app.config file. System.Configuration does not support config files for libraries. -->
  <system.serviceModel>
    <services>
      <service name="WcfServiceLibrary.MessageService">
        <endpoint address="" binding="basicHttpBinding" contract="WcfServiceLibrary.IMessageService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8733/WcfServiceLibrary/MessageService/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, 
          set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

</configuration>

What am I doing wrong? Is the general approach OK?

Upvotes: 2

Views: 251

Answers (2)

Sharkz
Sharkz

Reputation: 458

Your main error is

The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.

You need to specify the right connection string in the config file.

The other error is a consequence of the first error.

Upvotes: 1

The Unculled Badger
The Unculled Badger

Reputation: 760

the clue is in the error message. you need a connection string entry in the config file so that ef knows where to get its context from

Upvotes: 0

Related Questions