Add WCF reference within the same solution without adding a service reference - c#

I am working on a project using windows Azure and within an worker role i want to use a webservice to submit some information to it.My question is: Can i use the webservice without adding a service reference to it? or to add it in a certain way that when i publish my project in azure i don't need to change the service reference?

You can connect directly using a channel factory. Here's a sample base repository class, which you would override, where T is your Service Contract, such as IMyService,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.WindowsAzure.ServiceRuntime;
namespace pageengine.clients
{
public class RepositoryBase<T> : IDisposable
{
#region Channel
protected String roleName;
protected String serviceName;
protected String endpointName;
protected String protocol = #"http";
protected EndpointAddress _endpointAddress;
protected BasicHttpBinding httpBinding;
protected NetTcpBinding tcpBinding;
protected IChannelFactory channelFactory;
protected T client;
protected virtual AddressHeader[] addressHeaders
{
get
{
return null;
}
}
protected virtual EndpointAddress endpointAddress
{
get
{
if (_endpointAddress == null)
{
var endpoints = RoleEnvironment.Roles[roleName].Instances.Select(i => i.InstanceEndpoints[endpointName]).ToArray();
var endpointIP = endpoints.FirstOrDefault().IPEndpoint;
if(addressHeaders != null)
{
_endpointAddress = new EndpointAddress(new Uri(String.Format("{1}://{0}/{2}", endpointIP, protocol, serviceName)), addressHeaders);
}
else
{
_endpointAddress = new EndpointAddress(String.Format("{1}://{0}/{2}", endpointIP, protocol, serviceName));
}
}
return _endpointAddress;
}
}
protected virtual Binding binding
{
get
{
switch (protocol)
{
case "tcp.ip":
if (tcpBinding == null) tcpBinding = new NetTcpBinding();
return tcpBinding;
default:
//http
if (httpBinding == null) httpBinding = new BasicHttpBinding();
return httpBinding;
}
}
}
public virtual T Client
{
get
{
if (this.client == null)
{
this.channelFactory = new ChannelFactory<T>(binding, endpointAddress);
this.client = ((ChannelFactory<T>)channelFactory).CreateChannel();
((IContextChannel)client).OperationTimeout = TimeSpan.FromMinutes(2);
var scope = new OperationContextScope(((IContextChannel)client));
addCustomMessageHeaders(scope);
}
return this.client;
}
}
protected virtual void addCustomMessageHeaders(OperationContextScope operationContextScope)
{
// Overidden
}
#endregion
#region CTOR
public RepositoryBase()
{
}
#endregion
#region IDisposable Members
public virtual void Dispose()
{
if (client != null)
{
try
{
((ICommunicationObject)client).Close();
}
catch
{
try
{
((ICommunicationObject)client).Abort();
}
catch { } // Die quietly.
}
}
if (channelFactory != null)
{
try
{
channelFactory.Close();
}
catch
{
try
{
channelFactory.Abort();
}
catch { } // Die quietly.
}
channelFactory = null;
}
_endpointAddress = null;
httpBinding = null;
tcpBinding = null;
}
#endregion
}
}
You are then discovering the endpoint, which will work both in the published and emulated environments. A class extending this base might look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using pageengine.services.entities.account;
using pageengine.services;
namespace pageengine.clients.accounts
{
public class AccountsRepository : RepositoryBase<IAccounts>, IDisposable
{
#region CTOR
public AccountsRepository()
{
this.roleName = "EntitiesRole"; // Name of the role my service is on
this.endpointName = "HttpInternal"; // Name of the endpoint configured on that role. Can be internal or input, tcp or http.
this.serviceName = "Accounts.svc"; // Name of my service.
}
#endregion
}
}
Calls to your service (in this case from an MVC controller action) are then in the form of:
public ActionResult ListAccounts()
{
using (var accountsRepository = new AccountsRepository())
{
return View("ListAccounts", accountsRepository.Client.ListAccounts());
}
}

Related

WCF service return base class only

I'm working on a WCF service and trying to cleanup code. Issue I'm running into is I have a base data type I want to send as results from the service to the client; however in the service code itself it will mostly make use of classes derived on the base with additional properties for processing. The client has no reason to know about these at all.
Right now I can get this working but only if I define the derived classes in the shared library. I do not want them in there as they are specific solely to the service.
Below is example to show the problem. All three files are in separate projects in the same solution.
Common.IPersonService.cs
using System.ServiceModel;
using System.Runtime.Serialization;
namespace Common
{
[ServiceContract]
public interface IPersonService
{
[OperationContract(Name = "GetPersonById")]
Person GetPersonById(int id);
}
[DataContract(Name = "Person")]
public class Person
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
}
WcfClient.Program.cs
using System;
using System.ServiceModel;
using Common;
namespace WcfClient
{
class Program
{
static void Main(string[] args)
{
var binding = new NetTcpBinding();
var endpoint = new EndpointAddress("net.tcp://localhost:8001/WcfTest/");
var factory = new ChannelFactory<IPersonService>(binding, endpoint);
IPersonService service = null;
try
{
service = factory.CreateChannel();
Person result = service.GetPersonById(5);
Console.WriteLine(result.Name);
((ICommunicationObject)service).Close();
Console.ReadLine();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}
}
WcfService.Program.cs
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using Common;
namespace WcfService
{
[DataContract(Name = "Person")]
public class Contact : Person
{
public string Address { get; set; }
}
class Program
{
static void Main(string[] args)
{
using (ServiceHost serviceHost = new ServiceHost(typeof(PersonService)))
{
serviceHost.Open();
Console.WriteLine("Service started");
Console.ReadLine();
}
}
}
public class PersonService : IPersonService
{
private Dictionary<int, Contact> _testData = new Dictionary<int, Contact>();
public PersonService()
{
Random rnd = new Random();
for (int i = 0; i < 100; i++)
{
_testData.Add(i + 1, new Contact()
{
Id = i + 1,
Name = Guid.NewGuid().ToString(),
Address = Guid.NewGuid().ToString()
});
}
}
public static void Configure(ServiceConfiguration config)
{
config.AddServiceEndpoint(typeof(IPersonService), new NetTcpBinding(), "net.tcp://localhost:8001/WcfTest/");
config.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
}
public Person GetPersonById(int id)
{
return _testData[id];
}
public Person GetValueByKey(string key)
{
return null;
}
}
}
The exception received is the following:
The socket connection was aborted. This could be caused by an error
processing your message or a receive timeout being exceeded by the
remote host, or an underlying network resource issue. Local socket
timeout was '00:00:59.9780000'.
Now if I move the Contact class from the WcfService project and put it in the Common project it will work. As said though I'd prefer not to muddy a common library with items specific to the service implementation.
Thanks!

MVVM adding a list from a static service into the view?

I have created a service (static methods), which will get for instance all folders within google drive and returning a List<File>. (those methods are async MSDN Async Programming)
The problem is I dont know how to pass my results into the view. I tried to using a ObservableCollection but I cant make it work.
And one more thing is that Im not sure if its in my usage useful.
I dont add one item or delete one item. I just scrap the whole folders every refresh. What I have understood is that this is useful for a collection of data which will edited by the user.
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
var service = DriveHelper.createDriveService("client_secret.json", false)
// ERROR
_googleDriveFolders = new NotifyTaskCompletion<List<File>>( DriveHelper.getFiles(service), "trashed=false and mimeType = 'application/vnd.google-apps.folder'"));
}
public NotifyTaskCompletion<List<File>> googleDriveFolders { get; private set; }
private ObservableCollection<File> _googleDriveFolders;
public ObservableCollection<File> googleDriveFolder
{
get { return _googleDriveFolders; }
set
{
_googleDriveFolders = value;
RaisePropertyChanged();
}
}
//...
As noted in the comments, the issue is that your NotifyTaskCompletion immediately returns and gets assigned to the refreshFoldersCommand (btw. in C# naming conventions properties are in Pascal Case aka Camel Uppercase, not Camel lower case notation) property and the event is raised up immediately and not after the async operation finishes.
It's very bad practice to put async code into the ViewModels constructor (or any constructor for that case), because inside a constructor you can't await the async method.
There is no easy solution for it. The correct solution requires you to change your applications architecture and make use of a navigation service. I've posted it a few times already here on StackOverflow.
Prism (Microsoft's MVVM Framework) does come with a clean solution. It has an INavigationAware interface, that contains 3 methods (OnNagivatedTo, OnNavigatedFrom and IsNavigatioNTarget). To async load data into your ViewModel, NavigateTo is the important one.
In Prism it is called, after the previous View was unloaded (after calling NavigateFrom in the former ViewModels class) and the newly one has been instantiated and assigned to the new View. Parameters passed to theNavigationService.Navigate(..)method are passed toOnNagivatedTo` method of the ViewModel.
It can be marked as async and you can put your code there and await it
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
}
public NotifyTaskCompletion<List<File>> googleDriveFolders { get; private set; }
private ObservableCollection<File> _googleDriveFolders;
public ObservableCollection<File> googleDriveFolder
{
get { return _googleDriveFolders; }
set
{
_googleDriveFolders = value;
RaisePropertyChanged();
}
}
public async void OnNavigatedTo(NavigationContext context)
{
var service = DriveHelper.createDriveService("client_secret.json", false)
// ERROR
googleDriveFolder = await DriveHelper.getFiles(service), "trashed=false and mimeType = 'application/vnd.google-apps.folder'");
}
...
}
Edit:
Further answers about the same issue:
Pass parameter to a constructor in the ViewModel
How can I open another view in WPF MVVM using click handlers and commands? (Is my solution reasonable?)
Edit 2:
Also, you are assigning your NotifyTaskCompletion to _googleDriveFolders which is your backing field for the googleDriveFolder property, hence the RaisePropertyChanged(); is never called.
**Edit 3: **
As of your code from that tutorial, your code isn't exactly following the tutorial. The guy in the tutorial is binding to the property NotifyTaskCompletion. You are binding it to the backing field though.
public MainWindowViewModel()
{
var service = DriveHelper.createDriveService("client_secret.json", false)
// your property is named googleDriveFolders, but you are assigning it to _googleDriveFolders
googleDriveFolders = new NotifyTaskCompletion<List<File>>( DriveHelper.getFiles(service), "trashed=false and mimeType = 'application/vnd.google-apps.folder'"));
}
This code, when complete, won't call RaisePropertyChanged("googleDriveFolder") (which is your observable list), because NotifyTaskCompletion will only refresh it's own property. It's very likely you have bounded your View to the googleDriveFolder (Observable property) rather than to googleDriveFolders.Result.
For this example it's imperative to bind to googleDriveFolders.Result, because the change notification will only get fired for the Result Property of the NotificationTaskCompletition object as seen in the examples code propertyChanged(this, new PropertyChangedEventArgs("Result"));.
So your XAML has to look something like
<ListView Source="{Binding googleDriveFolders.Result}"/>
But anyhows, the issue still remains, that it's bad practice to do async operations within the constructor, so even within your Unit Tests for example, it would start the async task everytime the object is initialized, so in every UnitTest even if you test different stuff and you can't pass parameters to it easily (like passing a link or a folder name which to load).
So the clean way is doing it via navigation service and an INavigationAware implementation for ViewModels that require it (modes that do not do any async operation just don't implement this interface).
I came to this solution ... But I think this isn't the best way. <.<
Using a Listview.
namespace UpdateUploader.ViewModels
{
using System.Windows.Input;
using Helper;
using Services;
using System.Collections;
using System.Collections.ObjectModel;
using Google.Apis.Drive.v2.Data;
using Google.Apis.Drive.v2;
using System.Collections.Generic;
public class MainWindowViewModel : ViewModelBase
{
DriveService _service;
public MainWindowViewModel()
{
_service = DriveHelper.createDriveService("client_secret.json", false);
googleDriveFolders = new NotifyTaskCompletion<List<File>>( DriveHelper.getFiles(_service, "trashed=false and mimeType = 'application/vnd.google-apps.folder'"));
}
public NotifyTaskCompletion<List<File>> _googleDriveFolders;
public NotifyTaskCompletion<List<File>> googleDriveFolders
{
get { return _googleDriveFolders; }
set
{
_googleDriveFolders = value;
RaisePropertyChanged();
}
}
#region ICommands
private ICommand _refreshFoldersCommand;
public ICommand refreshFoldersCommand
{
get
{
if (this._refreshFoldersCommand == null)
{
_refreshFoldersCommand = new RelayCommand(p => this.loadFolders(p));
}
return this._refreshFoldersCommand;
}
}
#endregion ICommands
public void loadFolders(object parameter)
{
googleDriveFolders = new NotifyTaskCompletion<List<File>>(DriveHelper.getFiles(_service, "trashed=false and mimeType = 'application/vnd.google-apps.folder'"));
}
}
}
EDIT
NotifyTaskCompletion.cs
namespace UpdateUploader.Helper
{
using System;
using System.ComponentModel;
using System.Threading.Tasks;
public sealed class NotifyTaskCompletion<TResult> : INotifyPropertyChanged
{
public NotifyTaskCompletion(System.Threading.Tasks.Task<TResult> task)
{
Task = task;
if (!task.IsCompleted)
{
var _ = WatchTaskAsync(task);
}
}
private async Task WatchTaskAsync(Task task)
{
try
{
await task;
}
catch
{
}
var propertyChanged = PropertyChanged;
if (propertyChanged == null)
return;
propertyChanged(this, new PropertyChangedEventArgs("Status"));
propertyChanged(this, new PropertyChangedEventArgs("IsCompleted"));
propertyChanged(this, new PropertyChangedEventArgs("IsNotCompleted"));
if (task.IsCanceled)
{
propertyChanged(this, new PropertyChangedEventArgs("IsCanceled"));
}
else if (task.IsFaulted)
{
propertyChanged(this, new PropertyChangedEventArgs("IsFaulted"));
propertyChanged(this, new PropertyChangedEventArgs("Exception"));
propertyChanged(this, new PropertyChangedEventArgs("InnerException"));
propertyChanged(this, new PropertyChangedEventArgs("ErrorMessage"));
}
else
{
propertyChanged(this, new PropertyChangedEventArgs("IsSuccessfullyCompleted"));
propertyChanged(this, new PropertyChangedEventArgs("Result"));
}
}
public Task<TResult> Task { get; private set; }
public TResult Result
{
get { return (Task.Status == TaskStatus.RanToCompletion) ? Task.Result : default(TResult); }
}
public TaskStatus Status { get { return Task.Status; } }
public bool IsCompleted { get { return Task.IsCompleted; } }
public bool IsNotCompleted { get { return !Task.IsCompleted; } }
public bool IsSuccessfullyCompleted
{
get
{
return Task.Status == TaskStatus.RanToCompletion;
}
}
public bool IsCanceled { get { return Task.IsCanceled; } }
public bool IsFaulted { get { return Task.IsFaulted; } }
public AggregateException Exception { get { return Task.Exception; } }
public Exception InnerException
{
get
{
return (Exception == null) ? null : Exception.InnerException;
}
}
public string ErrorMessage
{
get
{
return (InnerException == null) ? null : InnerException.Message;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
DriveService.cs(excerpt; createDriveService, getfiles)
namespace UpdateUploader.Services
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v2;
using Google.Apis.Drive.v2.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using Google.Apis.Upload;
class DriveHelper
{
private static bool _unique;
public static DriveService createDriveService(string passFilePath, bool createUniqueID)
{
_unique = createUniqueID;
if (!System.IO.File.Exists(passFilePath))
{
Console.Error.WriteLine("keyfile not found...");
return null;
}
string[] scopes = new string[] { DriveService.Scope.Drive }; // Full accces
// loading the key file
UserCredential credential;
using (var stream = new System.IO.FileStream("client_secret.json", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = System.IO.Path.Combine(credPath, ".credentials/update-uploader");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Update Uploader",
});
return service;
}
// search = null ; get all files/folders
public static async Task<List<File>> getFiles(DriveService service, string search)
{
System.Collections.Generic.List<File> Files = new System.Collections.Generic.List<File>();
try
{
// list all files with max 1000 results
FilesResource.ListRequest list = service.Files.List();
list.MaxResults = 1000;
if (search != null)
{
list.Q = search;
}
FileList filesFeed = await list.ExecuteAsync();
while (filesFeed.Items != null)
{
foreach (File item in filesFeed.Items)
{
Files.Add(item);
}
// if it is the last page break
if (filesFeed.NextPageToken == null)
{
break;
}
list.PageToken = filesFeed.NextPageToken;
filesFeed = list.Execute();
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
return Files;
}
ViewModelBase.cs
namespace UpdateUploader.Helper
{
using System.ComponentModel;
using System.Runtime.CompilerServices;
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
// new since 4.6 or 4.5
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

MSMQ binding mismatch

We have a setup that used to work and has stopped sometime over the past few months. We use a custom dead-letter queue that is specified in config but basically gets set like this::
MsmqIntegrationBinding msmq = new MsmqIntegrationBinding(
// Defaults to WindowsDomain. We want all messages to be authenticated.
MsmqIntegrationSecurityMode.Transport);
msmq.DeadLetterQueue = DeadLetterQueue.Custom;
msmq.CustomDeadLetterQueue = new Uri("net.msmq://localhost/private/BulkUpdatesDeadLetter");
We've started getting this error, which seems to be pretty clear:
System.InvalidOperationException: A mismatch occurred between the binding and the MSMQ configuration. Messages cannot be sent. The custom dead letter queue specified in the binding must be a transactional queue. Ensure that the custom dead letter queue address is correct and the queue is a transactional queue.
We've verified both that we are pointing to the correct queue in the config and that the queue is transactional. Are there any other issues that might cause this exception to be thrown, or are we just missing something in the obvious?
Update: Had our web ops team delete and recreate the queues and still receiving the error.
The following code is provided by Microsoft corporation in the article BindingsSection.cs source code in C# .NET
namespace System.ServiceModel.Configuration
{
using System.Configuration;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Xml;
using System.Security;
public sealed partial class BindingsSection : ConfigurationSection, IConfigurationContextProviderInternal
{
static Configuration configuration = null;
ConfigurationPropertyCollection properties;
public BindingsSection() { }
Dictionary<string, bindingcollectionelement=""> BindingCollectionElements
{
get
{
Dictionary<string, bindingcollectionelement=""> bindingCollectionElements = new Dictionary<string, bindingcollectionelement="">();
foreach (ConfigurationProperty property in this.Properties)
{
bindingCollectionElements.Add(property.Name, this[property.Name]);
}
return bindingCollectionElements;
}
}
new public BindingCollectionElement this[string binding]
{
get
{
return (BindingCollectionElement)base[binding];
}
}
protected override ConfigurationPropertyCollection Properties
{
get
{
if (this.properties == null)
{
this.properties = new ConfigurationPropertyCollection();
}
this.UpdateBindingSections();
return this.properties;
}
}
[ConfigurationProperty(ConfigurationStrings.BasicHttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public BasicHttpBindingCollectionElement BasicHttpBinding
{
get { return (BasicHttpBindingCollectionElement)base[ConfigurationStrings.BasicHttpBindingCollectionElementName]; }
}
// This property should only be called/set from BindingsSectionGroup TryAdd
static Configuration Configuration
{
get { return BindingsSection.configuration; }
set { BindingsSection.configuration = value; }
}
[ConfigurationProperty(ConfigurationStrings.CustomBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public CustomBindingCollectionElement CustomBinding
{
get { return (CustomBindingCollectionElement)base[ConfigurationStrings.CustomBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.MsmqIntegrationBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public MsmqIntegrationBindingCollectionElement MsmqIntegrationBinding
{
get { return (MsmqIntegrationBindingCollectionElement)base[ConfigurationStrings.MsmqIntegrationBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.NetPeerTcpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public NetPeerTcpBindingCollectionElement NetPeerTcpBinding
{
get { return (NetPeerTcpBindingCollectionElement)base[ConfigurationStrings.NetPeerTcpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.NetMsmqBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public NetMsmqBindingCollectionElement NetMsmqBinding
{
get { return (NetMsmqBindingCollectionElement)base[ConfigurationStrings.NetMsmqBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.NetNamedPipeBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public NetNamedPipeBindingCollectionElement NetNamedPipeBinding
{
get { return (NetNamedPipeBindingCollectionElement)base[ConfigurationStrings.NetNamedPipeBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.NetTcpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public NetTcpBindingCollectionElement NetTcpBinding
{
get { return (NetTcpBindingCollectionElement)base[ConfigurationStrings.NetTcpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.WSFederationHttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public WSFederationHttpBindingCollectionElement WSFederationHttpBinding
{
get { return (WSFederationHttpBindingCollectionElement)base[ConfigurationStrings.WSFederationHttpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.WS2007FederationHttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public WS2007FederationHttpBindingCollectionElement WS2007FederationHttpBinding
{
get { return (WS2007FederationHttpBindingCollectionElement)base[ConfigurationStrings.WS2007FederationHttpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.WSHttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public WSHttpBindingCollectionElement WSHttpBinding
{
get { return (WSHttpBindingCollectionElement)base[ConfigurationStrings.WSHttpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.WS2007HttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public WS2007HttpBindingCollectionElement WS2007HttpBinding
{
get { return (WS2007HttpBindingCollectionElement)base[ConfigurationStrings.WS2007HttpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.WSDualHttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public WSDualHttpBindingCollectionElement WSDualHttpBinding
{
get { return (WSDualHttpBindingCollectionElement)base[ConfigurationStrings.WSDualHttpBindingCollectionElementName]; }
}
public static BindingsSection GetSection(Configuration config)
{
if (config == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("config");
}
return (BindingsSection)config.GetSection(ConfigurationStrings.BindingsSectionGroupPath);
}
public List<bindingcollectionelement> BindingCollections
{
get
{
List<bindingcollectionelement> bindingCollections = new List<bindingcollectionelement>();
foreach (ConfigurationProperty property in this.Properties)
{
bindingCollections.Add(this[property.Name]);
}
return bindingCollections;
}
}
internal static bool TryAdd(string name, Binding binding, Configuration config, out string bindingSectionName)
{
bool retval = false;
BindingsSection.Configuration = config;
try
{
retval = BindingsSection.TryAdd(name, binding, out bindingSectionName);
}
finally
{
BindingsSection.Configuration = null;
}
return retval;
}
internal static bool TryAdd(string name, Binding binding, out string bindingSectionName)
{
// TryAdd built on assumption that BindingsSectionGroup.Configuration is valid.
// This should be protected at the callers site. If assumption is invalid, then
// configuration system is in an indeterminate state. Need to stop in a manner that
// user code can not capture.
if (null == BindingsSection.Configuration)
{
DiagnosticUtility.DebugAssert("The TryAdd(string name, Binding binding, Configuration config, out string binding) variant of this function should always be called first. The Configuration object is not set.");
DiagnosticUtility.FailFast("The TryAdd(string name, Binding binding, Configuration config, out string binding) variant of this function should always be called first. The Configuration object is not set.");
}
bool retval = false;
string outBindingSectionName = null;
BindingsSection sectionGroup = BindingsSection.GetSection(BindingsSection.Configuration);
sectionGroup.UpdateBindingSections();
foreach (string sectionName in sectionGroup.BindingCollectionElements.Keys)
{
BindingCollectionElement bindingCollectionElement = sectionGroup.BindingCollectionElements[sectionName];
// Save the custom bindings as the last choice
if (!(bindingCollectionElement is CustomBindingCollectionElement))
{
MethodInfo tryAddMethod = bindingCollectionElement.GetType().GetMethod("TryAdd", BindingFlags.Instance | BindingFlags.NonPublic);
if (tryAddMethod != null)
{
retval = (bool)tryAddMethod.Invoke(bindingCollectionElement, new object[] { name, binding, BindingsSection.Configuration });
if (retval)
{
outBindingSectionName = sectionName;
break;
}
}
}
}
if (!retval)
{
// Much of the time, the custombinding should come out ok.
CustomBindingCollectionElement customBindingSection = CustomBindingCollectionElement.GetBindingCollectionElement();
retval = customBindingSection.TryAdd(name, binding, BindingsSection.Configuration);
if (retval)
{
outBindingSectionName = ConfigurationStrings.CustomBindingCollectionElementName;
}
}
// This little oddity exists to make sure that the out param is assigned to before the method
// exits.
bindingSectionName = outBindingSectionName;
return retval;
}
/// <securitynote>
/// Critical - uses SecurityCritical method UnsafeLookupCollection which elevates
/// Safe - does not leak config objects
/// </securitynote>
[SecurityCritical, SecurityTreatAsSafe]
void UpdateBindingSections()
{
ExtensionElementCollection bindingExtensions = ExtensionsSection.UnsafeLookupCollection(ConfigurationStrings.BindingExtensions, ConfigurationHelpers.GetEvaluationContext(this));
// Extension collections are additive only (BasicMap) and do not allow for <clear>
// or <remove> tags, nor do they allow for overriding an entry. This allows us
// to optimize this to only walk the binding extension collection if the counts
// mismatch.
if (bindingExtensions.Count != this.properties.Count)
{
foreach (ExtensionElement bindingExtension in bindingExtensions)
{
if (null != bindingExtension)
{
if (!this.properties.Contains(bindingExtension.Name))
{
ConfigurationProperty property = new ConfigurationProperty(bindingExtension.Name,
Type.GetType(bindingExtension.Type, true),
null,
ConfigurationPropertyOptions.None);
this.properties.Add(property);
}
}
}
}
}
/// <securitynote>
/// Critical - uses SecurityCritical method UnsafeGetAssociatedBindingCollectionElement which elevates
/// Safe - does not leak config objects
/// </securitynote>
[SecurityCritical, SecurityTreatAsSafe]
internal static void ValidateBindingReference(string binding, string bindingConfiguration, ContextInformation evaluationContext, ConfigurationElement configurationElement)
{
// ValidateBindingReference built on assumption that evaluationContext is valid.
// This should be protected at the callers site. If assumption is invalid, then
// configuration system is in an indeterminate state. Need to stop in a manner that
// user code can not capture.
if (null == evaluationContext)
{
DiagnosticUtility.DebugAssert("ValidateBindingReference() should only called with valid ContextInformation");
DiagnosticUtility.FailFast("ValidateBindingReference() should only called with valid ContextInformation");
}
if (!String.IsNullOrEmpty(binding))
{
BindingCollectionElement bindingCollectionElement = null;
if (null != evaluationContext)
{
bindingCollectionElement = ConfigurationHelpers.UnsafeGetAssociatedBindingCollectionElement(evaluationContext, binding);
}
else
{
bindingCollectionElement = ConfigurationHelpers.UnsafeGetBindingCollectionElement(binding);
}
if (bindingCollectionElement == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigInvalidSection,
ConfigurationHelpers.GetBindingsSectionPath(binding)),
configurationElement.ElementInformation.Source,
configurationElement.ElementInformation.LineNumber));
}
if (!String.IsNullOrEmpty(bindingConfiguration))
{
if (!bindingCollectionElement.ContainsKey(bindingConfiguration))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigInvalidBindingName,
bindingConfiguration,
ConfigurationHelpers.GetBindingsSectionPath(binding),
ConfigurationStrings.BindingConfiguration),
configurationElement.ElementInformation.Source,
configurationElement.ElementInformation.LineNumber));
}
}
}
}
ContextInformation IConfigurationContextProviderInternal.GetEvaluationContext()
{
return this.EvaluationContext;
}
/// <securitynote>
/// RequiresReview - the return value will be used for a security decision -- see comment in interface definition
/// </securitynote>
ContextInformation IConfigurationContextProviderInternal.GetOriginalEvaluationContext()
{
DiagnosticUtility.DebugAssert("Not implemented: IConfigurationContextProviderInternal.GetOriginalEvaluationContext");
return null;
}
}
}
</remove></clear></bindingcollectionelement></bindingcollectionelement></bindingcollectionelement></string,></string,></string,>

How to make WCF set a connection string for use with EntityFramework

Using EntityFramework, I have an auto-generated file with:
namespace Chaos.Data
{
public partial class ChaosModel : OpenAccessContext, IChaosModelUnitOfWork
{
private static string connectionStringName = #"ChaosLibraryConnection";
private static BackendConfiguration backend = GetBackendConfiguration();
private static MetadataSource metadataSource = XmlMetadataSource.FromAssemblyResource("EntitiesModel.rlinq");
public ChaosModel()
:base(connectionStringName, backend, metadataSource)
{ }
public ChaosModel(string connection)
:base(connection, backend, metadataSource)
{ }
......................
In the WCF Service, I am using:
namespace Chaos.DataService
{
[ServiceContract]
public class ChaosService
{
[OperationContract]
public IEnumerable<Encountertime> GetEncounterTimes(DateTime? encountertime)
{
if (encountertime == null) return null;
using (var context = new ChaosModel())
{
var query = from et in context.Encountertimes
where et.Tencounter.Date == ((DateTime)encountertime).Date
select et;
var result = context.CreateDetachedCopy(query.ToList());
return result;
}
}
.............................
How can I make the WCF service on startup execute a method (once) that will return a new connection string so that I can change the calls to ChaosModel() to:
using (var context = new ChaosModel(connectionString))
(I am looking for a way to add a static constructor within the WCF service--or something better?).
(The method will determine the network I am on and construct an appropriate connection string to the network server.)
Note: I can make no changes to the auto-generated Entity file.
Use static constructor.
[ServiceContract]
public class ChaosService
{
private static string connectionString;
static ChaosService(){
connectionString = your logic...
}
[OperationContract]
public IEnumerable<Encountertime> GetEncounterTimes(DateTime? encountertime)
{
using (var context = new ChaosModel(connectionString))
{
...
}
}
}
or eventually a singleton pattern:
public class ConnectionInfo
{
public string ConnectionString { get; private set; }
private ConnectionInfo()
{
var connectionstring = string.Empty;
//some logic
this.ConnectionString = connectionstring;
}
private static ConnectionInfo current;
public static ConnectionInfo Current {
get {
if (current != null)
current = new ConnectionInfo();
return current;
}
}
}
[OperationContract]
public IEnumerable<Encountertime> GetEncounterTimes(DateTime? encountertime)
{
using (var context = new ChaosModel(ConnectionInfo.Current.ConnectionString))
{
...
}
}

Debugging Data-Service-Request-Exception on WCF-Data-Service during add new entity

this is my service code :
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.Linq.Expressions;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
using System.Web;
namespace RadAppSilver.Web
{
public class DsWFS006 : DataService<WFS006Entities>
{
public DsWFS006()
{
ServiceHost host = new ServiceHost(typeof(DsWFS006));
ServiceDebugBehavior debug = host.Description.Behaviors.Find<ServiceDebugBehavior>();
// if not found - add behavior with setting turned on
if (debug == null)
{
host.Description.Behaviors.Add(
new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
}
else
{
// make sure setting is turned ON
if (!debug.IncludeExceptionDetailInFaults)
{
debug.IncludeExceptionDetailInFaults = true;
}
}
host.Open();
// This method is called only once to initialize service-wide policies.
}
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
//config.SetEntitySetPageSize("DocDetail", 30);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
}
}
I need to debug when I'm going to new record to my entity error happened but update entity works fine :
private void Grid1RowEditEnded(object sender, Telerik.Windows.Controls.GridViewRowEditEndedEventArgs e)
{
if (e.EditAction == Telerik.Windows.Controls.GridView.GridViewEditAction.Commit)
{
doc.AccNo = string.IsNullOrEmpty(SelectedAcc) ? doc.AccNo : SelectedAcc;
if (e.EditOperationType == Telerik.Windows.Controls.GridView.GridViewEditOperationType.Edit)
{
service.UpdateObject(doc);
}
else if (e.EditOperationType == Telerik.Windows.Controls.GridView.GridViewEditOperationType.Insert)
{
(this.grid1.ItemsSource as VirtualQueryableCollectionView).Add(doc);
service.AddObject("DocDetail", doc);
}
service.BeginSaveChanges(OnChangesSaved, service);
}
}
private void OnChangesSaved(IAsyncResult result)
{
Dispatcher.BeginInvoke(() =>
{
service = result.AsyncState as DS1.WFS006Entities;
try
{
service.EndSaveChanges(result);
}
catch (DataServiceRequestException ex)
{
MessageBox.Show(ex.Response.ToString());
}
catch (InvalidOperationException ex)
{
MessageBox.Show(ex.Message);
}
});
}
and this code include initializing service on my client :
private void SetContext()
{
service = new DSEntity();
DataServiceQuery<DS1.Accounts> queryAcc = (DataServiceQuery<DS1.Accounts>)
(service.Accounts.Select(m =>
new DS1.Accounts
{
AccNo = m.AccNo,
AccDesc = m.AccDesc
}));
queryAcc.BeginExecute(t =>
{
DataServiceQuery<DS1.Accounts> state = t.AsyncState as DataServiceQuery<DS1.Accounts>;
var executedState = state.EndExecute(t);
ObservableCollection<DS1.Accounts> data = new ObservableCollection<DS1.Accounts>();
foreach (var entity in executedState)
data.Add(entity);
AccCache = data.ToList();
}, queryAcc);
var view = new VirtualQueryableCollectionView() { LoadSize = 300, VirtualItemCount = 10000 };
view.ItemsLoading += (y, e) =>
{
DataServiceQuery<DS1.DocDetail> query = (DataServiceQuery<DS1.DocDetail>)
service.DocDetail.OrderBy(it => it.Item)
.Where<DS1.DocDetail>(it => it.DocSerNo == 91120001)
.Where(view.FilterDescriptors)
.Sort(view.SortDescriptors)
.Skip(e.StartIndex)
.Take(e.ItemCount);
query = query.IncludeTotalCount();
query.BeginExecute(
s =>
{
DataServiceQuery<DS1.DocDetail> state = s.AsyncState as DataServiceQuery<DS1.DocDetail>;
var executedState = state.EndExecute(s);
var response = executedState as QueryOperationResponse<DS1.DocDetail>;
int count = (int)response.TotalCount;
ObservableCollection<DS1.DocDetail> data = new ObservableCollection<DS1.DocDetail>();
foreach (var entity in executedState)
data.Add(entity);
var dataSource = data.ToList();
view.VirtualItemCount = count;
view.Load(e.StartIndex, dataSource);
}, query);
};
grid1.ItemsSource = view;
}
it doesn't work while add new object and exception doesn't give me any detail when I add host.open(); on constructor to show exception detail the service has been stop.
Include all the option for debugging the wcf service
1.Apply the following attribute to your service class
[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
Override the following two methods in your service class
a. protected override void OnStartProcessingRequest(ProcessRequestArgs args)
b,protected override void HandleException(HandleExceptionArgs args)
set the break points on these two methods and see what type of exception.

Categories

Resources