Imagine the following XAML:
<Page
x:Class="MyProject.MainPage"
xmlns:local="using:MyProject">
<local:MyStackPanel>
<Button Content="Go" Click="OnGo"/>
</local:MyStackPanel>
</Page>
XAML assumes that OnGois a method in the page class. Can I somehow tell it declaratively that OnGo resides in MyStackPanel instead?
I know I can assign the event handler programmatically once the page is loaded. I'm wondering if it's possible by purely XAML means. "No" is an acceptable answer :)
For your requirement, you could bind the MyStackPanel DataContext with itself. Then create BtnClickCommand that used to bind button command in the MyStackPanel class like following.
public class MyStackPanel : StackPanel
{
public MyStackPanel()
{
}
public ICommand BtnClickCommand
{
get
{
return new RelayCommand(() =>
{
});
}
}
}
public class RelayCommand : ICommand
{
private readonly Action _execute;
private readonly Func<bool> _canExecute;
/// <summary>
/// Raised when RaiseCanExecuteChanged is called.
/// </summary>
public event EventHandler CanExecuteChanged;
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action execute, Func<bool> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
/// <summary>
/// Determines whether this RelayCommand can execute in its current state.
/// </summary>
/// <param name="parameter">
/// Data used by the command. If the command does not require data to be passed,
/// this object can be set to null.
/// </param>
/// <returns>true if this command can be executed; otherwise, false.</returns>
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute();
}
/// <summary>
/// Executes the RelayCommand on the current command target.
/// </summary>
/// <param name="parameter">
/// Data used by the command. If the command does not require data to be passed,
/// this object can be set to null.
/// </param>
public void Execute(object parameter)
{
_execute();
}
/// <summary>
/// Method used to raise the CanExecuteChanged event
/// to indicate that the return value of the CanExecute
/// method has changed.
/// </summary>
public void RaiseCanExecuteChanged()
{
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
Usage
<local:MyStackPanel DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
<Button Command="{Binding BtnClickCommand}" Content="ClickMe" />
</local:MyStackPanel>
Related
I have the following custom required attribute code:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public sealed class AddressRequiredAttribute : RequiredAttribute, IClientValidatable
{
/// <summary>
/// The _property name
/// </summary>
private string _propertyName;
/// <summary>
/// Initializes a new instance of the <see cref="AddressRequiredAttribute"/> class.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
public AddressRequiredAttribute(string propertyName)
: base()
{
_propertyName = propertyName;
}
/// <summary>
/// Checks that the value of the required data field is not empty.
/// </summary>
/// <param name="value">The data field value to validate.</param>
/// <returns>
/// true if validation is successful; otherwise, false.
/// </returns>
protected override ValidationResult IsValid(object value, ValidationContext context)
{
if (context.ObjectType.BaseType == typeof(AddressModel))
{
PropertyInfo property = context.ObjectType.GetProperty(_propertyName);
if (property != null && (bool)property.GetValue(context.ObjectInstance))
{
return base.IsValid(value, context);
}
}
return ValidationResult.Success;
}
/// <summary>
/// When implemented in a class, returns client validation rules for that class.
/// </summary>
/// <param name="metadata">The model metadata.</param>
/// <param name="context">The controller context.</param>
/// <returns>
/// The client validation rules for this validator.
/// </returns>
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
string errorMessage = this.ErrorMessage;
// Get the specific error message if set, otherwise the default
if (string.IsNullOrEmpty(errorMessage) && metadata != null)
{
errorMessage = FormatErrorMessage(metadata.GetDisplayName());
}
var clientValidationRule = new ModelClientValidationRule()
{
ErrorMessage = errorMessage,
ValidationType = "requiredaddress"
};
return new[] { clientValidationRule };
}
and the following jquery for the client side validation which is run on window.load:
$.validator.addMethod('requiredaddress', function (value, element, params) {
return value != '';
}, '');
$.validator.unobtrusive.adapters.add('requiredaddress', {}, function (options) {
options.rules['requiredaddress'] = true;
options.messages['requiredaddress'] = options.message;
});
However, the clientside doesn't kick in so I get the normal clientside validation working, then the form will submit but come back with the custom errors after postback. All the examples that I have looked at say that my code should be correct so I'm not sure what is wrong here.
Can anyone see anything obvious I'm doing wrong here, thanks
I did something similar to this and found that if I put the code in the document.ready on window.load it wouldn't work. In the end I went with using the following code placed after the jquery validate scripts:
(function ($) {
$.validator.addMethod('requiredaddress', function (value, element, params) {
return value != '';
}, 'Clientside Should Not Postback');
// i think you should be able to use this as your adapter
$.validator.unobtrusive.adapters.addBool('requiredaddress');
})(jQuery);
I am using VB Framework 4.0 and Linq to sql.
I want to choose dynamycally the name of table. I have used the library namedtable.dll and I have mapped all the tables of database and it's Ok.
My problem is when I try to execute executequery. Here my code.
Imports Microsoft.VisualBasic
Imports System.Data.Linq
Imports Prototype.NamedTable.Data
Imports Prototype.NamedTable.Utility
Public Class tipos
Private _conexion As String = "conexion"
Public Sub New()
End Sub
...........
Public Function getConsulta(byval tableName as String) As IList(Of TIPOS)
Dim context As New DataContext(_conexion)
sql = " select COD, NAME from " & tableName
Dim a = context.ExecuteQuery(Of TIPOS)(sql)
Return sql.ToList
End Function
End Class
but I have an error: "El tipo 'TIPOS' debe declarar un constructor predeterminado (sin parámetros) para que pueda construirse durante la asignación." that in English is:
"The type 'Type TIPOS' must declare a default (parameterless) constructor in order to be constructed during mapping"
I have defined "TIPOS" in other file:
Public Interface TIPOS
<Column(CanBeNull:=False)> Property COD Integer
<Column(CanBeNull:=False)> Property NAME As String
End Interface
Public Class ITIPO : Implements TIPO
Private _cod As Integer
Private _name As String
Public Property COD As Integer Implements TIPO.COD
Get
Return _cod
End Get
Set(ByVal value As Integer)
_cod = value
End Set
End Property
Public Property NAME As String Implements TIPO.NAME
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
End Class
I need help!
Sorry for my English.
The solution can be found on codeproject.com in article "Dynamic Table Mapping for LINQ-to-SQL." Below is a static class you can use. Please see the article for instructions on what you must do to use the 4 different generic methods. Here is an invocation example:
public interface IResult
{
[Column(IsPrimaryKey = true)]
int Id { get; set; }
[Column]
string Name { get; set; }
[Column]
double Value { get; set; }
}
public void TestThis()
{
var connectionString = "Data Source=.\SQLEXPRESS;Initial Catalog=YourDatabaseName;Integrated Security=True;Pooling=False";
var context = new DataContext(connectionString);
var table = context.GetTable<IResult>("YourTableName");
var query = from r in table where r.Id == 108 select r;
var list = query.ToList();
}
Class Code:
namespace Prototype.NamedTable
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
/// <summary>
/// The utility.
/// </summary>
public static class Utility
{
#region Constants and Fields
/// <summary>
/// The named types.
/// </summary>
private static readonly Dictionary<string, Type> NamedTypes = new Dictionary<string, Type>();
/// <summary>
/// The _assembly builder.
/// </summary>
private static AssemblyBuilder _assemblyBuilder;
/// <summary>
/// The _module builder.
/// </summary>
private static ModuleBuilder _moduleBuilder;
#endregion
#region Properties
/// <summary>
/// Gets or sets a value indicating whether Verbose.
/// </summary>
public static bool Verbose { get; set; }
#endregion
#region Public Methods
/// <summary>
/// The clear.
/// </summary>
public static void Clear()
{
_assemblyBuilder = null;
NamedTypes.Clear();
}
/// <summary>
/// Retrieve a table from the data context which implements ITable<TEntity> by T and use ITable<TBack>
/// </summary>
/// <typeparam name="TEntity">
/// Entity Type
/// </typeparam>
/// <typeparam name="TBack">
/// Backing Type
/// </typeparam>
/// <param name="context">
/// Data Context
/// </param>
/// <returns>
/// </returns>
public static ATable<TEntity> GetTable<TEntity, TBack>(this DataContext context) where TEntity : class
where TBack : class
{
// Create the backup table
Table<TBack> refer = context.GetTable<TBack>();
// Prepare the cloning method
Delegate cloneFrom = CompileCloning(typeof(TEntity), typeof(TBack));
// Construct the table wrapper
return new ATable<TEntity>(refer, cloneFrom);
}
/// <summary>
/// Retrieve a table from the data context which implements ITable<TEntity> uses specific backing table
/// </summary>
/// <typeparam name="TEntity">
/// Entity Type
/// </typeparam>
/// <param name="context">
/// Data context
/// </param>
/// <param name="name">
/// Table name
/// </param>
/// <returns>
/// </returns>
public static ATable<TEntity> GetTable<TEntity>(this DataContext context, string name) where TEntity : class
{
// Create/Retrieve a type definition for the table using the TEntity type
Type type = DefineEntityType(typeof(TEntity), name);
// Create the backup table using the new type
ITable refer = context.GetTable(type);
// Prepare the cloning method
Delegate cloneFrom = CompileCloning(typeof(TEntity), type);
// Construct the table wrapper
return new ATable<TEntity>(refer, cloneFrom);
}
/*
/// <summary>
/// The log.
/// </summary>
/// <param name="format">
/// The format.
/// </param>
/// <param name="args">
/// The args.
/// </param>
public static void Log(string format, params object[] args)
{
if (!Verbose)
{
return;
}
Console.Write("*** ");
if ((args == null) || (args.Length == 0))
{
Console.WriteLine(format);
}
else
{
Console.WriteLine(format, args);
}
}*/
#endregion
#region Methods
/// <summary>
/// Clone an attribute
/// </summary>
/// <param name="attr">
/// </param>
/// <returns>
/// </returns>
private static CustomAttributeBuilder CloneColumn(object attr)
{
Type source = attr.GetType();
Type target = typeof(ColumnAttribute);
var props = new List<PropertyInfo>();
var values = new List<object>();
// Extract properties and their values
foreach (PropertyInfo prop in source.GetProperties())
{
if (!prop.CanRead || !prop.CanWrite)
{
continue;
}
props.Add(target.GetProperty(prop.Name));
values.Add(prop.GetValue(attr, null));
}
// Create a new attribute using the properties and values
return new CustomAttributeBuilder(
target.GetConstructor(Type.EmptyTypes), new object[0], props.ToArray(), values.ToArray());
}
/// <summary>
/// Make a delegate that copy content from "source" to "dest"
/// </summary>
/// <param name="source">
/// Source Type
/// </param>
/// <param name="dest">
/// Destination Type
/// </param>
/// <returns>
/// Executable delegate
/// </returns>
private static Delegate CompileCloning(Type source, Type dest)
{
// Input parameter
ParameterExpression input = Expression.Parameter(source);
// For every property, create a member binding
List<MemberBinding> binds =
source.GetProperties().Select(
prop =>
Expression.Bind(
dest.GetProperty(
prop.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly),
Expression.MakeMemberAccess(input, prop))).Cast<MemberBinding>().ToList();
// Expression of creating the new object
MemberInitExpression body = Expression.MemberInit(
Expression.New(dest.GetConstructor(Type.EmptyTypes)), binds);
// The final lambda
LambdaExpression lambda = Expression.Lambda(body, input);
// MJE
//Log("{0}", lambda.ToString());
// Return the executable delegate
return lambda.Compile();
}
/// <summary>
/// Create a class based on the template interface
/// </summary>
/// <param name="template">
/// </param>
/// <param name="name">
/// </param>
/// <returns>
/// </returns>
private static Type DefineEntityType(Type template, string name)
{
// Prepare the builders if not done
if (_assemblyBuilder == null)
{
_assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
_moduleBuilder = _assemblyBuilder.DefineDynamicModule("Types");
}
// Check if there is already a type created for that table
if (NamedTypes.ContainsKey(name))
{
return NamedTypes[name];
}
// Create the new type
TypeBuilder tbuilder = null;
if (template.IsInterface)
{
tbuilder = DefineInterfaceChild(name, template);
}
else
{
tbuilder = DefineOverriddenChild(name, template);
}
Type final = tbuilder.CreateType();
NamedTypes[name] = final;
return final;
}
/// <summary>
/// The define interface child.
/// </summary>
/// <param name="name">
/// The name.
/// </param>
/// <param name="template">
/// The template.
/// </param>
/// <returns>
/// </returns>
private static TypeBuilder DefineInterfaceChild(string name, Type template)
{
TypeBuilder tbuilder = _moduleBuilder.DefineType(
name, TypeAttributes.Public, typeof(Object), new[] { template });
// Default constructor
tbuilder.DefineDefaultConstructor(MethodAttributes.Public);
// Attach Table attribute
var abuilder = new CustomAttributeBuilder(
typeof(TableAttribute).GetConstructor(Type.EmptyTypes),
new object[0],
new[] { typeof(TableAttribute).GetProperty("Name") },
new object[] { name });
tbuilder.SetCustomAttribute(abuilder);
List<PropertyInfo> properties = template.GetProperties().ToList(); // May require sorting
// Implement all properties));
foreach (PropertyInfo prop in properties)
{
// Define backing field
FieldBuilder fbuilder = tbuilder.DefineField(
"_" + prop.Name, prop.PropertyType, FieldAttributes.Private);
// Define get method
MethodBuilder pgbuilder = tbuilder.DefineMethod(
"get_" + prop.Name,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
| MethodAttributes.Virtual | MethodAttributes.Final,
prop.PropertyType,
Type.EmptyTypes);
// Define get method body { return _field; }
ILGenerator ilg = pgbuilder.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_0);
ilg.Emit(OpCodes.Ldfld, fbuilder);
ilg.Emit(OpCodes.Ret);
// Define set method
MethodBuilder psbuilder = tbuilder.DefineMethod(
"set_" + prop.Name,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
| MethodAttributes.Virtual | MethodAttributes.Final,
null,
new[] { prop.PropertyType });
// Define set method body { _field = value; }
ILGenerator ils = psbuilder.GetILGenerator();
ils.Emit(OpCodes.Ldarg_0);
ils.Emit(OpCodes.Ldarg_1);
ils.Emit(OpCodes.Stfld, fbuilder);
ils.Emit(OpCodes.Ret);
// Define the property
PropertyBuilder pbuilder = tbuilder.DefineProperty(
prop.Name, PropertyAttributes.None, CallingConventions.Standard, prop.PropertyType, null);
// Set get/set method
pbuilder.SetGetMethod(pgbuilder);
pbuilder.SetSetMethod(psbuilder);
// Attach Column attribute
foreach (object attr in prop.GetCustomAttributes(false))
{
if (attr is ColumnAttribute || attr is AlterColumnAttribute)
{
// MJE
//Log("Create column attribute for {0}", prop.Name);
pbuilder.SetCustomAttribute(CloneColumn(attr));
break;
}
}
}
return tbuilder;
}
/// <summary>
/// The define overridden child.
/// </summary>
/// <param name="name">
/// The name.
/// </param>
/// <param name="template">
/// The template.
/// </param>
/// <returns>
/// </returns>
private static TypeBuilder DefineOverriddenChild(string name, Type template)
{
TypeBuilder tbuilder = _moduleBuilder.DefineType(name, TypeAttributes.Public, template);
// Default constructor
tbuilder.DefineDefaultConstructor(MethodAttributes.Public);
// Attach Table attribute
var abuilder = new CustomAttributeBuilder(
typeof(TableAttribute).GetConstructor(Type.EmptyTypes),
new object[0],
new[] { typeof(TableAttribute).GetProperty("Name") },
new object[] { name });
tbuilder.SetCustomAttribute(abuilder);
List<PropertyInfo> properties = template.GetProperties().ToList(); // May require sorting
// Implement all properties));
foreach (PropertyInfo prop in properties)
{
// Define get method
MethodBuilder pgbuilder = tbuilder.DefineMethod(
"get_" + prop.Name,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
| MethodAttributes.Virtual | MethodAttributes.Final,
prop.PropertyType,
Type.EmptyTypes);
// Define get method body { return _field; }
ILGenerator ilg = pgbuilder.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_0);
ilg.Emit(OpCodes.Call, template.GetMethod("get_" + prop.Name));
ilg.Emit(OpCodes.Ret);
// Define set method
MethodBuilder psbuilder = tbuilder.DefineMethod(
"set_" + prop.Name,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
| MethodAttributes.Virtual | MethodAttributes.Final,
null,
new[] { prop.PropertyType });
// Define set method body { _field = value; }
ILGenerator ils = psbuilder.GetILGenerator();
ils.Emit(OpCodes.Ldarg_0);
ils.Emit(OpCodes.Ldarg_1);
ils.Emit(OpCodes.Call, template.GetMethod("set_" + prop.Name));
ils.Emit(OpCodes.Ret);
// Define the property
PropertyBuilder pbuilder = tbuilder.DefineProperty(
prop.Name, PropertyAttributes.None, CallingConventions.Standard, prop.PropertyType, null);
// Set get/set method
pbuilder.SetGetMethod(pgbuilder);
pbuilder.SetSetMethod(psbuilder);
// Attach Column attribute
foreach (object attr in prop.GetCustomAttributes(false))
{
if (attr is ColumnAttribute || attr is AlterColumnAttribute)
{
// MJE
//Log("Create column attribute for {0}", prop.Name);
pbuilder.SetCustomAttribute(CloneColumn(attr));
break;
}
}
}
return tbuilder;
}
#endregion
/// <summary>
/// A table wrapper implements ITable<TEntity> backed by other ITable object
/// </summary>
/// <typeparam name="TEntity">
/// </typeparam>
public class ATable<TEntity> : ITable<TEntity>
where TEntity : class
{
#region Constants and Fields
/// <summary>
/// Cloning method
/// </summary>
private readonly Delegate _clone;
/// <summary>
/// Backing table
/// </summary>
private readonly ITable _internal;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="ATable{TEntity}"/> class.
/// Construct from backing table
/// </summary>
/// <param name="inter">
/// </param>
/// <param name="from">
/// </param>
public ATable(ITable inter, Delegate from)
{
this._internal = inter;
this._clone = from;
}
#endregion
#region Properties
/// <summary>
/// Gets ElementType.
/// </summary>
public Type ElementType
{
get
{
// Use the backing table element
return this._internal.ElementType;
}
}
/// <summary>
/// Gets Expression.
/// </summary>
public Expression Expression
{
get
{
// Use the backing table expression
return this._internal.Expression;
}
}
/// <summary>
/// Gets Provider.
/// </summary>
public IQueryProvider Provider
{
get
{
// Use the backing table provider
return this._internal.Provider;
}
}
#endregion
#region Implemented Interfaces
#region IEnumerable
/// <summary>
/// The get enumerator.
/// </summary>
/// <returns>
/// </returns>
/// <exception cref="NotImplementedException">
/// </exception>
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
#region IEnumerable<TEntity>
/// <summary>
/// The get enumerator.
/// </summary>
/// <returns>
/// </returns>
/// <exception cref="NotImplementedException">
/// </exception>
public IEnumerator<TEntity> GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
#region ITable<TEntity>
/// <summary>
/// The attach.
/// </summary>
/// <param name="entity">
/// The entity.
/// </param>
/// <exception cref="NotImplementedException">
/// </exception>
public void Attach(TEntity entity)
{
throw new NotImplementedException();
}
/// <summary>
/// The delete on submit.
/// </summary>
/// <param name="entity">
/// The entity.
/// </param>
public void DeleteOnSubmit(TEntity entity)
{
// Directly invoke the backing table
this._internal.DeleteOnSubmit(entity);
}
/// <summary>
/// The insert on submit.
/// </summary>
/// <param name="entity">
/// The entity.
/// </param>
public void InsertOnSubmit(TEntity entity)
{
// Input entity must be changed to backing type
object v = this._clone.DynamicInvoke(entity);
// Invoke the backing table
this._internal.InsertOnSubmit(v);
}
#endregion
#endregion
}
/// <summary>
/// The alter column attribute.
/// </summary>
public class AlterColumnAttribute : Attribute
{
#region Constants and Fields
/// <summary>
/// The _can be null.
/// </summary>
private bool _canBeNull = true;
/// <summary>
/// The _update check.
/// </summary>
private UpdateCheck _updateCheck = UpdateCheck.Always;
#endregion
#region Properties
/// <summary>
/// Gets or sets AutoSync.
/// </summary>
public AutoSync AutoSync { get; set; }
/// <summary>
/// Gets or sets a value indicating whether CanBeNull.
/// </summary>
public bool CanBeNull
{
get
{
return this._canBeNull;
}
set
{
this._canBeNull = value;
}
}
/// <summary>
/// Gets or sets DbType.
/// </summary>
public string DbType { get; set; }
/// <summary>
/// Gets or sets Expression.
/// </summary>
public string Expression { get; set; }
/// <summary>
/// Gets or sets a value indicating whether IsDbGenerated.
/// </summary>
public bool IsDbGenerated { get; set; }
/// <summary>
/// Gets or sets a value indicating whether IsDiscriminator.
/// </summary>
public bool IsDiscriminator { get; set; }
/// <summary>
/// Gets or sets a value indicating whether IsPrimaryKey.
/// </summary>
public bool IsPrimaryKey { get; set; }
/// <summary>
/// Gets or sets a value indicating whether IsVersion.
/// </summary>
public bool IsVersion { get; set; }
/// <summary>
/// Gets or sets UpdateCheck.
/// </summary>
public UpdateCheck UpdateCheck
{
get
{
return this._updateCheck;
}
set
{
this._updateCheck = value;
}
}
#endregion
}
}
}
Linq-to-Sql cannot materialize interfaces. It needs a class specification to know what instances it should create from a query. The exception message is elusive, to say the least. I don't know why it isn't more to the point.
Note that the class you want to materialize must have been mapped, or: it must be in the dbml. I say this because your ITIPO class is not partial, which makes me wonder how you can make it implement an interface (well, maybe you just slimmed down the code).
Side note: don't use all capitals for class names, and prefix an interface specification with "I", not a class.
I'm currently experiencing some issues with workflow services.
They work fine if I start 4, 5 in short sequence, but if I increase this value (starting from ~10) then I get the following exception:
This channel can no longer be used to send messages as the output session was auto-closed due to a server-initiated shutdown. Either disable auto-close by setting the DispatchRuntime.AutomaticInputSessionShutdown to false, or consider modifying the shutdown protocol with the remote server.
I think that the problem is in the way I create proxies. I use the following code to provide proxies, attempting to reuse existing ones:
public abstract class ProxyProvider<TService>
where TService : class
{
/// <summary>
/// Static reference to the current time provider.
/// </summary>
private static ProxyProvider<TService> current = DefaultProxyProvider.Instance;
private TService service;
/// <summary>
/// Gets or sets the current time provider.
/// </summary>
/// <value>
/// The current time provider.
/// </value>
public static ProxyProvider<TService> Current
{
get
{
return ProxyProvider<TService>.current;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
ProxyProvider<TService>.current = value;
}
}
/// <summary>
/// Resets to default.
/// </summary>
public static void ResetToDefault()
{
ProxyProvider<TService>.current = DefaultProxyProvider.Instance;
}
/// <summary>
/// Loads the proxy.
/// </summary>
/// <param name="forceNew">if set to <c>true</c> [force new].</param>
/// <returns>The instance of the proxy.</returns>
public virtual TService Provide(bool forceNew = false)
{
if (forceNew || !this.IsInstanceValid())
{
this.service = this.CreateInstance();
return this.service;
}
return this.service;
}
/// <summary>
/// Internals the load.
/// </summary>
/// <returns>The new created service.</returns>
protected abstract TService CreateInstance();
private bool IsInstanceValid()
{
var instance = this.service as ICommunicationObject;
if (instance == null)
{
return false;
}
return instance.State != CommunicationState.Faulted && instance.State != CommunicationState.Closed && instance.State != CommunicationState.Closing;
}
/// <summary>
/// Defines the default <see cref="ProxyProvider<TService>"/> which uses the System DateTime.UtcNow value.
/// </summary>
private sealed class DefaultProxyProvider : ProxyProvider<TService>
{
/// <summary>
/// Reference to the instance of the <see cref="ProxyProvider<TService>"/>.
/// </summary>
private static ProxyProvider<TService> instance;
/// <summary>
/// Gets the instance.
/// </summary>
public static ProxyProvider<TService> Instance
{
get
{
if (DefaultProxyProvider.instance == null)
{
DefaultProxyProvider.instance = new DefaultProxyProvider();
}
return DefaultProxyProvider.instance;
}
}
/// <summary>
/// Loads the specified force new.
/// </summary>
/// <returns>A non-disposed instance of the given service.</returns>
protected override TService CreateInstance()
{
var loadedService = Activator.CreateInstance<TService>();
return loadedService;
}
}
With an additional "lazy" provider:
public class CustomConstructorProxyProvider<TService> : ProxyProvider<TService>
where TService : class
{
private readonly Func<TService> constructor;
/// <summary>
/// Initializes a new instance of the <see cref="CustomConstructorProxyProvider<TService>"/> class.
/// </summary>
/// <param name="constructor">The constructor.</param>
public CustomConstructorProxyProvider(Func<TService> constructor)
{
this.constructor = constructor;
}
/// <summary>
/// Internals the load.
/// </summary>
/// <returns>The new created service.</returns>
protected override TService CreateInstance()
{
var service = this.constructor();
return service;
}
}
Used this way:
var proxy = ProxyProvider<IWorkflowService>.Current.Provide();
proxy.DoSomething();
Initialized like this:
ProxyProvider<IWorkflowService>.Current = new CustomConstructorProxyProvider<IWorkflowService>(() => new WorkflowServiceProxy("endpoint"));
Workflow services are hosted by IIS and I added the following throttling settings:
<serviceThrottling
maxConcurrentCalls="512"
maxConcurrentInstances="2147483647"
maxConcurrentSessions="1024"/>
which should be enough for my needs.
I hope that someone can help me configuring client and server to have achieve the desired scalability (a few hundreds started in sequence and running in parallel, using the WorkflowInstance sql store).
UPDATE:
I'm using NetTcpBinding for all services.
UPDATE 2:
All services are hosted and consumed by now locally.
Thanks
Francesco
Im writing a routing service for some WCF services. I want to use a custom message filter that filters out my message.
Here is my custom message filter:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel.Dispatcher;
using System.IO;
using System.Xml;
namespace AMA_ISE.Router.MessageFilter
{
/// <summary>
/// This message filter implements the custom filtering for the routing services to re-route the incoming messages
/// correctly.
/// </summary>
public class CustomMessageFilter : System.ServiceModel.Dispatcher.MessageFilter
{
/// <summary>
/// The sales channel for which the filter is configured.
/// </summary>
private string _salesChannel;
/// <summary>
/// The service, for which the filter is configured.
/// </summary>
private string _service;
/// <summary>
/// Initializes a new instance of the <see cref="CustomMessageFilter"/> class.
/// </summary>
/// <param name="messageData">The message data.</param>
public CustomMessageFilter(string messageData)
{
var splitted = messageData.Split("|".ToCharArray());
_salesChannel = splitted[0];
_service = splitted[1];
}
/// <summary>
/// When overridden in a derived class, tests whether a message satisfies the filter criteria. The body cannot be examined.
/// </summary>
/// <param name="message">The <see cref="T:System.ServiceModel.Channels.Message"/> object to test.</param>
/// <returns>
/// true if the <see cref="T:System.ServiceModel.Channels.Message"/> object satisfies the filter criteria; otherwise, false.
/// </returns>
public override bool Match(System.ServiceModel.Channels.Message message)
{
return true;
}
/// <summary>
/// When overridden in a derived class, tests whether a buffered message satisfies the criteria of a filter.
/// </summary>
/// <param name="buffer">The <see cref="T:System.ServiceModel.Channels.MessageBuffer"/> object to test.</param>
/// <returns>
/// true if the <see cref="T:System.ServiceModel.Channels.MessageBuffer"/> object satisfies the filter criteria; otherwise, false.
/// </returns>
public override bool Match(System.ServiceModel.Channels.MessageBuffer buffer)
{
using (var memStream = new MemoryStream())
{
var msgText = GetMessageEnvelope(buffer);
// check sales channel
if (GetValueByTagName(msgText, "SalesChannel") != _salesChannel)
return false;
// check the requested service
var toValue = GetValueByTagName(msgText, "To");
File.AppendAllText("C:\\temp\\filter.txt", toValue + " - " + _service + " - " + toValue.Trim().EndsWith(_service) + "\r\n");
return toValue.Trim().EndsWith(_service);
}
}
/// <summary>
/// Gets the message envelope.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <returns></returns>
private static string GetMessageEnvelope(System.ServiceModel.Channels.MessageBuffer buffer)
{
using (MemoryStream memStream = new MemoryStream())
{
var msg = buffer.CreateMessage();
XmlDictionaryWriter xmlDictWriter =
XmlDictionaryWriter.CreateTextWriter(memStream);
msg.WriteMessage(xmlDictWriter);
xmlDictWriter.Flush();
memStream.Seek(0, SeekOrigin.Begin);
var reader = new StreamReader(memStream);
var text = reader.ReadToEnd();
return text;
}
}
/// <summary>
/// Gets the name of the value by tag.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="tagName">Name of the tag which content we are searching for.</param>
/// <returns></returns>
private static string GetValueByTagName(string text, string tagName)
{
var txt = text.Substring(text.IndexOf("<" + tagName+" ") + 1);
txt = txt.Substring(txt.IndexOf(">") + 1);
return txt.Substring(0, txt.IndexOf("<"));
}
}
}
As you can see, Im writing some information in a log file located in c:\temp. I expect to match the current filter when Match() returns true; that is not happening. When using this filter, I have the following text file:
http://localhost/AMA-ISE.Router/BookingService.svc - RetrieveService.svc - False
http://localhost/AMA-ISE.Router/BookingService.svc - CancelService.svc - False
http://localhost/AMA-ISE.Router/BookingService.svc - BookingService.svc - True
http://localhost/AMA-ISE.Router/BookingService.svc - AvailService.svc - False
http://localhost/AMA-ISE.Router/BookingService.svc - RebookingService.svc - False
That Looks nice, the BookingService.svc does fits and Match() will give true back. But it doesnt work. When I now use the routing service, I get the following error:
Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: No matching MessageFilter was found for the given Message.
Whats wrong? Have I misunderstood something with the message filters? Please help me!
Michael Baarz
not all XML are formed in the same manner. Sometimes tags containing namespaces directly and sometimes the namespace is prefixed and used. That was why my method has not worked. Here is the working code for a custom filter manager (maybe someone is interested in):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel.Dispatcher;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace AMA_ISE.Router.MessageFilter
{
/// <summary>
/// This message filter implements the custom filtering for the routing services to re-route the incoming messages
/// correctly.
/// </summary>
public class CustomMessageFilter : System.ServiceModel.Dispatcher.MessageFilter
{
/// <summary>
/// The sales channel for which the filter is configured.
/// </summary>
private string _salesChannel;
/// <summary>
/// The service, for which the filter is configured.
/// </summary>
private string _service;
/// <summary>
/// Initializes a new instance of the <see cref="CustomMessageFilter"/> class.
/// </summary>
/// <param name="messageData">The message data.</param>
public CustomMessageFilter(string messageData)
{
var splitted = messageData.Split("|".ToCharArray());
_salesChannel = splitted[0];
_service = splitted[1];
}
/// <summary>
/// When overridden in a derived class, tests whether a message satisfies the filter criteria. The body cannot be examined.
/// </summary>
/// <param name="message">The <see cref="T:System.ServiceModel.Channels.Message"/> object to test.</param>
/// <returns>
/// true if the <see cref="T:System.ServiceModel.Channels.Message"/> object satisfies the filter criteria; otherwise, false.
/// </returns>
public override bool Match(System.ServiceModel.Channels.Message message)
{
return true;
}
static int counter = 0;
/// <summary>
/// When overridden in a derived class, tests whether a buffered message satisfies the criteria of a filter.
/// </summary>
/// <param name="buffer">The <see cref="T:System.ServiceModel.Channels.MessageBuffer"/> object to test.</param>
/// <returns>
/// true if the <see cref="T:System.ServiceModel.Channels.MessageBuffer"/> object satisfies the filter criteria; otherwise, false.
/// </returns>
public override bool Match(System.ServiceModel.Channels.MessageBuffer buffer)
{
using (var memStream = new MemoryStream())
{
var document = GetMessageEnvelope(buffer);
var salesChannel = GetValueOfNamedNode(document.Root, "SalesChannel");
var toService = GetValueOfNamedNode(document.Root, "To");
return salesChannel == _salesChannel && toService.EndsWith(_service);
}
}
private static string GetValueOfNamedNode(XElement element, string findName)
{
if (element.Name.LocalName == findName)
return element.Value;
foreach (var ele in element.Elements())
{
var foundValue = GetValueOfNamedNode(ele, findName);
if (foundValue != null)
return foundValue;
}
return null;
}
/// <summary>
/// Gets the message envelope.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <returns></returns>
private static XDocument GetMessageEnvelope(System.ServiceModel.Channels.MessageBuffer buffer)
{
using (MemoryStream memStream = new MemoryStream())
{
var msg = buffer.CreateMessage();
XmlDictionaryWriter xmlDictWriter =
XmlDictionaryWriter.CreateTextWriter(memStream);
msg.WriteMessage(xmlDictWriter);
xmlDictWriter.Flush();
memStream.Seek(0, SeekOrigin.Begin);
var doc = XDocument.Load(memStream);
return doc;
}
}
}
}
I have the following in my root ResourceDictionary. The Foreground = Red part works, but the custom attached dependency property does not get set.
I can set it manually through code, but I obviously want to avoid having to set it for every textbox. Does this work in Silverlight? I have seen some posts about doing it in WPF, and my code looks right (to me).
<Style TargetType="TextBox">
<Setter Property="controls:TextBoxContextMenu.HasContextMenu" Value="True" />
<Setter Property="Foreground" Value="Red" />
</Style>
/// <summary>
/// Gets the value of the HasContextMenu attached property for a specified TextBox.
/// </summary>
/// <param name="element">The TextBox from which the property value is read.</param>
/// <returns>The HasContextMenu property value for the TextBox.</returns>
public static bool GetHasContextMenu(TextBox element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool)element.GetValue(HasContextMenuProperty);
}
/// <summary>
/// Sets the value of the HasContextMenu attached property to a specified TextBox.
/// </summary>
/// <param name="element">The TextBox to which the attached property is written.</param>
/// <param name="value">The needed HasContextMenu value.</param>
public static void SetHasContextMenu(TextBox element, bool value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(HasContextMenuProperty, value);
}
/// <summary>
/// Identifies the HasContextMenu dependency property.
/// </summary>
public static readonly DependencyProperty HasContextMenuProperty =
DependencyProperty.RegisterAttached(
"HasContextMenu",
typeof(bool),
typeof(TextBox),
new PropertyMetadata(false, OnHasContextMenuPropertyChanged));
/// <summary>
/// HasContextMenuProperty property changed handler.
/// </summary>
/// <param name="d">TextBoxContextMenu that changed its HasContextMenu.</param>
/// <param name="e">Event arguments.</param>
private static void OnHasContextMenuPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// code
}
I should add that the attached dependency property is defined in a class which inherits from RadContextMenu, which is a DependencyObject (I have been reading and somewhere it is suggested that this can't work if the attached property is defined in such a class, but this seems strange)
I figured it out. It was indeed due to having the attached property defined in the class I have.
To fix it, i created a new class called TextBoxContextMenuService and put the code in there instead.