Свой RemotingProxy

 
0
 
.NET
ava
Shit_happenes | 15.08.2007, 14:11
Как такое сделать?

При вызове с клиента метода по ремоутингу можно передавать CallContext с добавленными свойствами -
CallContext.SetHeaders(header);
remoteObject.Hello();
При последующем вызове надо повторить первую срочку -
CallContext.SetHeaders(header);
remoteObject.Connect();

Как сделать так, чтобы свой прокси каждый раз делал CallContext.SetHeaders(header);
при вызове любого метода???

т.е. на клиенте код будет -
remoteObject.Hello();
remoteObject.Connect();
а прокси автоматически перед каждым вызовом метода добавит CallContext.SetHeaders(header);
Comments (22)
ava
tol05 | 15.08.2007, 13:47 #
ну так и создавай свой собственный RealProxy. И в его методе

public override IMessage Invoke(IMessage myIMessage){}

пропиши вызов

CallContext.SetHeaders(header);


P.S. а вообще в следующий раз:
1. давай сразу код, чтоб ответы были конкретными
2. пользуйся кнопкой "Код" над полем редактирования... очень облегчает жизнь читателям твоего вопроса...
smile
ava
Shit_happenes | 15.08.2007, 14:27 #

namespace RemSample
{
[AttributeUsage( AttributeTargets.Class)]
public class ProxyTestAttribute : ProxyAttribute
{
public override MarshalByRefObject CreateInstance(Type serverType)
{
MarshalByRefObject target = base.CreateInstance(serverType);
ProxyTest p = new ProxyTest(serverType, target);
return (MarshalByRefObject)p.GetTransparentProxy();
}
}
public class ProxyTest : RealProxy
{
MarshalByRefObject _target;
Type _type;
public ProxyTest(Type type, MarshalByRefObject target)
{
Console.WriteLine("ProxyTest!!!");
_type = type;
_target = target;
}
public override IMessage Invoke(IMessage msg)
{
Header[] head = new Header[1];
head[0] = new Header("User", "UserName");
CallContext.SetHeaders(head);
return msg;
}
}
}


Вот такой вот код моего прокси.
Только таким образом клиент падает на вызове метода.
ava
Shit_happenes | 15.08.2007, 16:46 #

Изменил код в прокси -

public override IMessage Invoke(IMessage msg)
{
if (msg is IMethodCallMessage)
{
Header[] head = new Header[1];
head[0] = new Header("User", "UserName");
CallContext.SetHeaders(head);
return (IMethodCallMessage)msg;
}
return msg;
}


Теперь при вызове с клиента

ProxyTest pt = new ProxyTest(typeof(Foo), "tcp://localhost:8008/Foo.rem");
Foo foo = (Foo)pt.GetTransparentProxy();
Console.WriteLine(foo.Connect());

метода foo.Connect(),
.Net ругается "The method was called with a Message of an unexpected type."
ava
tol05 | 15.08.2007, 17:55 #
smile ты ВЕСЬ КОД можешь выложить? Сервера, клиента, удаленного объекта...
этот пример смотрел?
ava
Shit_happenes | 16.08.2007, 09:13 #
Код сервера -

class Server
{
static void Main(string[] args)
{
TcpChannel tcpChannel = new TcpChannel(8008);
ChannelServices.RegisterChannel(tcpChannel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Foo), "Foo.rem", WellKnownObjectMode.SingleCall);
Console.ReadKey();
}
}

Код Объекта -

public interface IFoo
{
string Hello();
string Connect();
}

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class Foo : MarshalByRefObject, IFoo
{
#region IFoo Members

public string Hello()
{
Console.WriteLine("Hello Begin!");
return "Hello!";
}

public string Connect()
{
return "Connect!";
}

#endregion
}


Код прокси, идентичен статье в MSDN -

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class ProxyTest : RealProxy
{
public ProxyTest(Type type)
: base(type)
{
// This constructor forwards the call to base RealProxy.
// RealProxy uses the Type to generate a transparent proxy
}

public override IMessage Invoke(IMessage myIMessage)
{
Console.WriteLine("MyProxy.Invoke Start");
Console.WriteLine("");
ReturnMessage myReturnMessage = null;

if (myIMessage is IMethodCallMessage)
{
Console.WriteLine("Message is of type 'IMethodCallMessage'.");
Console.WriteLine("");

IMethodCallMessage myIMethodCallMessage;
myIMethodCallMessage = (IMethodCallMessage)myIMessage;
Console.WriteLine("InArgCount is : " +
myIMethodCallMessage.InArgCount.ToString());

foreach (object myObj in myIMethodCallMessage.InArgs)
{
Console.WriteLine("InArgs is : " + myObj.ToString());
}

for (int i = 0; i < myIMethodCallMessage.InArgCount; i++)
{
Console.WriteLine("GetArgName(" + i.ToString() + ") is : " +
myIMethodCallMessage.GetArgName(i));
Console.WriteLine("GetInArg(" + i.ToString() + ") is : " +
myIMethodCallMessage.GetInArg(i).ToString());
}
Console.WriteLine("");
}
else if (myIMessage is IMethodReturnMessage)
Console.WriteLine("Message is of type 'IMethodReturnMessage'.");

// Build Return Message
myReturnMessage = new ReturnMessage(5, null, 0, null,
(IMethodCallMessage)myIMessage);

Console.WriteLine("MyProxy.Invoke - Finish");
return myReturnMessage;
}
}

Код клиента -

class Client
{
static void Main(string[] args)
{
TcpChannel tcp = new TcpChannel();
ChannelServices.RegisterChannel(tcp, false);
ProxyTest pt = new ProxyTest(typeof(Foo));
Foo foo = (Foo)pt.GetTransparentProxy();
Console.WriteLine(foo.Connect().ToString());
Console.WriteLine(foo.Hello().ToString());
Console.ReadKey();
}
}

При вызове foo.Connect() - выдает Exception -
"Return argument has an invalid type."
ava
Shit_happenes | 16.08.2007, 10:34 #
Всё, догнал.
Теперь всю логику вызова реального объекта надо переопределить в Invoke перед построением

myReturnMessage = new ReturnMessage(5,null,0,null,
(IMethodCallMessage)myIMessage);

первый параметр здесь и будет возвращаемое значение.

Заработало!!!
Благодарю за содействие.
ava
tol05 | 16.08.2007, 10:51 #
:biggrin пока писал тебе ответ, увидел твой пост... Но это еще не все, ИМХО.

1. Статью не нужно было воспринимать буквально. Ты сигнатуру конструктора ReturnMessage смотрел? первый параметр -
Цитата


The object returned by the invoked method from which the current ReturnMessage instance originated.

ты Invok-аешь метод Connect(), а он возвращает string. В конструктор же ты суешь 5, которое воспринимается как int...
напиши "5" - все работает.

Но это нам не нужно здесь...
Если хотя бы один из вызываемых клиентом методов будет иметь не-string возвращаемое значение (если Hello() например будет возвращать bool), то это опять не будет работать... На Hello() посыпется, опять не тот тип будет... Повторяю, статья - это просто пример.

2. Во-вторых, созданный прокси подменяет вызов метода своим методом Invoke, т.е. когда ты вызываешь remoteObject.Hello() - на самом деле вызовется только proxy.Invoke() . Иными словами при вызове любого метода у тебя всегда будет возвращено "5" smile
поэтому в proxy.Invoke() нужно добавить вызов целевого метода удаленного объекта.

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class ProxyTest :RealProxy
{
String myURIString;
MarshalByRefObject myMarshalByRefObject;

public ProxyTest(Type type) : base(type)
{
// RealProxy uses the Type to generate a transparent proxy.
myMarshalByRefObject = (MarshalByRefObject)Activator.CreateInstance((type));
// Get 'ObjRef', for transmission serialization between application domains.
ObjRef myObjRef = RemotingServices.Marshal(myMarshalByRefObject);
// Get the 'URI' property of 'ObjRef' and store it.
myURIString = myObjRef.URI;

}

public override IMessage Invoke(IMessage myIMessage)
{
Console.WriteLine("MyProxy.Invoke Start");
Console.WriteLine("");

if(myIMessage is IMethodCallMessage)
{
Console.WriteLine("Message is of type 'IMethodCallMessage'.");
Console.WriteLine("");

IMethodCallMessage myIMethodCallMessage = (IMethodCallMessage)myIMessage;

Console.WriteLine("InArgCount is : " + myIMethodCallMessage.InArgCount);

foreach(object myObj in myIMethodCallMessage.InArgs)
{
Console.WriteLine("InArgs is : " + myObj);
}

for(int i = 0; i < myIMethodCallMessage.InArgCount; i++)
{
Console.WriteLine("GetArgName(" + i + ") is : " + myIMethodCallMessage.GetArgName(i));
Console.WriteLine("GetInArg(" + i + ") is : " + myIMethodCallMessage.GetInArg(i));
}
Console.WriteLine("");
}
else if(myIMessage is IMethodReturnMessage)
Console.WriteLine("Message is of type 'IMethodReturnMessage'.");

Header[] head = new Header[1];
head[0] = new Header("User", "UserName");
CallContext.SetHeaders(head);

myIMessage.Properties["__Uri"] = myURIString;
// Build Return Message
IMessage myReturnMessage = ChannelServices.SyncDispatchMessage(myIMessage);
//new ReturnMessage("5", null, 0, null, (IMethodCallMessage)myIMessage);

Console.WriteLine("MyProxy.Invoke - Finish");
return myReturnMessage;
}
}
ava
Shit_happenes | 16.08.2007, 12:12 #
Я переписал Invoke следующим образом -

public override IMessage Invoke(IMessage myIMessage)
{
Console.WriteLine("MyProxy.Invoke Start");


IFoo foo = (IFoo)Activator.GetObject(typeof(IFoo), "tcp://localhost:8008/Foo.rem");
Header[] header = new Header[2];
header[0] = new Header("userName", "test");
header[1] = new Header("userPassword", "testtest");
CallContext.SetHeaders(header);
object obj = foo.Connect();
Header[] h = CallContext.GetHeaders();
// Build Return Message
myReturnMessage = new ReturnMessage(obj,null,0,null,
(IMethodCallMessage)myIMessage);

Console.WriteLine("MyProxy.Invoke - Finish");
return myReturnMessage;
}
}


Всё работает как и хотелось.
Может есть какие-то коментарии и пожелания?
ava
Shit_happenes | 16.08.2007, 12:33 #
Вопросик по твоему коду -


public ProxyTest(Type type) : base(type)
{
// RealProxy uses the Type to generate a transparent proxy.
myMarshalByRefObject = (MarshalByRefObject)Activator.CreateInstance((type));
// Get 'ObjRef', for transmission serialization between application domains.
ObjRef myObjRef = RemotingServices.Marshal(myMarshalByRefObject);
// Get the 'URI' property of 'ObjRef' and store it.
myURIString = myObjRef.URI;
}


Какое URI будет берется в этом случае?



ava
tol05 | 16.08.2007, 12:33 #
Цитата (Shit_happenes @ 16.8.2007, 12:12 findReferencedText)
IFoo foo = (IFoo)Activator.GetObject(typeof(IFoo), "tcp://localhost:8008/Foo.rem");
зачем?
и какой смысл в этом?

object obj = foo.Connect();

чтобы не писать на клиенте

CallContext.SetHeaders(header);
foo.Connect();

теперь нагородили кучу дополнительного кода и все равно пишем эти же две строчки? А как насчет foo.Hello();??
помнится мне ты и для Hello() хотел CallContext.SetHeaders(header); вызывать?
т.е. ты хочешь сказать, что на клиенте:

TcpChannel tcp = new TcpChannel();
ChannelServices.RegisterChannel(tcp, false);
ProxyTest pt = new ProxyTest(typeof(Foo));
Foo foo = (Foo)pt.GetTransparentProxy();
Console.WriteLine(foo.Connect().ToString()); //заходим в pt.Invoke(), создаем новый объект foo и вызываем foo.Connect(); еще раз???
Console.WriteLine(foo.Hello().ToString()); //заходим в pt.Invoke(), создаем новый объект foo и вызываем foo.Connect(); непонятно для чего???
Console.ReadKey();

посмотри тот пример, что я запостил. Фишка в том, что вызовы удаленного объекта заменяются на вызовы прокси, при этом в вызове прокси сначала идут дополнительные, нужные тебе операции, а потом уже прокси диспетчерезует вызов дальше (целевому удаленному объекту).

P.S. "Какое URI будет берется в этом случае?" - читай код. ссылка ObjRef твоего реального удаленного объекта, который активатор создает при создании прокси (прокси к этому же удаленному объекту создается, верно?)
ava
Shit_happenes | 16.08.2007, 12:37 #
Что-то я действительно сделал теже яйца только в профиль!!!

Сейчас твой примерчик испробую.


---
ссылка ObjRef твоего реального удаленного объекта, который активатор создает при создании прокси (прокси к этому же удаленному объекту создается, верно?)
---

код на клиенте -

ProxyTest pt = new ProxyTest(typeof(Foo));
Foo foo = (Foo)pt.GetTransparentProxy();
Console.WriteLine(foo.Connect().ToString());

Что-то не откуда брать Activatorу мой удаленный ури.
Скорее всего я его через конструктор передам.
ava
Shit_happenes | 16.08.2007, 13:30 #
В твоем примере ури берется локальный. т.е. все на клиенте создается.
а если ручками присвоить в Invoke myIMessage.Properties["__Uri"] = "tcp://localhost:8008/Foo.rem";
ругается что такого объекта не существует или сервер дисконект.

я без понятия что делать?!?
ava
Shit_happenes | 16.08.2007, 14:44 #
Можешь написать клиентский код?
ava
tol05 | 16.08.2007, 14:45 #
Цитата (Shit_happenes @ 16.8.2007, 13:30 findReferencedText)
В твоем примере ури берется локальный

а в твоем? smile

мы говорили и рассматривали ситуации, когда и сервер, и клиент, находятся на одной машине. Ты же и в своем примере на клиенте URI не указывал?

Сделай в своем прокси-классе конструктор

public ProxyTest(Type type, string uri) : base(type)
{
myMarshalByRefObject = (MarshalByRefObject)Activator.CreateInstance(type);
ObjRef myObjRef = RemotingServices.Marshal(myMarshalByRefObject, uri);
myURIString = uri;//myObjRef.URI;

}

myURIString прибивай к message. Вот и все.
ava
Shit_happenes | 16.08.2007, 15:06 #
короче, сделал как ты посоветовал. - прописал ури.
Вызываю метод Hello()

public string Hello()
{

Console.WriteLine("Hello Begin!");
Header[] header = CallContext.GetHeaders();
return "Hello!";
}

по идеи он должен на запущеном сервере писать в консоль Hello Begin!.
а он нифига не делает на сервере.
Ещё и header == null.


ava
tol05 | 16.08.2007, 18:26 #
Цитата (Shit_happenes @ 16.8.2007, 15:06 findReferencedText)
по идеи он должен на запущеном сервере писать в консоль Hello Begin!.

а он нифига не делает на сервере

у меня пишет... проверь на моем примере

Цитата (Shit_happenes @ 16.8.2007, 15:06 findReferencedText)
header == null

тут да, траблы... не разобрался сам до конца. Но если юзать CallContext.SetData(...), то работает.
удаленный объект

namespace FooDll
{
public interface IFoo
{
string Hello();
string Connect();
}

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class Foo :MarshalByRefObject, IFoo
{
#region IFoo Members
public string Hello()
{
Console.WriteLine("Hello Begin!");
return "Hello!";
}

public string Connect()
{
string datа = (string)CallContext.GetData("data");
return "Connect!" + data;

}

public override Object InitializeLifetimeService ()
{
return null;
}


#endregion
}
}

клиент

class Client
{
static void Main(string[] args)
{
TcpChannel tcp = new TcpChannel();
ChannelServices.RegisterChannel(tcp, false);
ProxyTest pt = new ProxyTest(typeof(Foo), "tcp://localhost:8008/Foo.rem");
Foo foo = (Foo)pt.GetTransparentProxy();
Console.WriteLine(foo.Connect());
Console.WriteLine(foo.Hello());
Console.ReadKey();
}
}

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class ProxyTest :RealProxy
{
String myURIString;
MarshalByRefObject myMarshalByRefObject;

public ProxyTest(Type type, string uri) : base(type)
{
// RealProxy uses the Type to generate a transparent proxy.

myMarshalByRefObject = (MarshalByRefObject)Activator.CreateInstance(type);
// Get 'ObjRef', for transmission serialization between application domains.
ObjRef myObjRef = RemotingServices.Marshal(myMarshalByRefObject, uri);
// Get the 'URI' property of 'ObjRef' and store it.
myURIString = uri;//myObjRef.URI;

}

public override IMessage Invoke(IMessage myIMessage)
{
Console.WriteLine("MyProxy.Invoke Start");
Console.WriteLine("");

//Header[] head = new Header[1];
//head[0] = new Header("User", "UserName");
//CallContext.SetHeaders(head);

myIMessage.Properties["__Uri"] = myURIString;
// Build Return Message
CallContext.SetData("data", "xss");//SetHeaders(head);
IMessage myReturnMessage = ChannelServices.SyncDispatchMessage(myIMessage);

Console.WriteLine("MyProxy.Invoke - Finish");
return myReturnMessage;
}
}

}
сервер

namespace RemotingProxy
{
class Server
{
static void Main(string[] args)
{
TcpChannel tcpChannel = new TcpChannel(8008);
ChannelServices.RegisterChannel(tcpChannel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Foo), "Foo.rem", WellKnownObjectMode.SingleCall);
Console.ReadKey();
}
}

}

ava
Shit_happenes | 17.08.2007, 10:38 #
Не, не пишет ничего на сервере.
Пишет в запушенном клиенте, всё то что должен писать на сервере.
Похоже, что объект полностью скопировался на клиент и там выполняется.
Это не то что надо.

Но зато GetData работает. Уже что-то.

Вот попробовал переделать пример из Маклина - "MS .Net Remoting".
Прокси работает, всё пишет там где положенно, вот только контекст ничего не передает,
а Маклин утверждает, что должен контекст передаваться.
Вот код прокси

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class MyProxy : RealProxy
{
String _uri;
MarshalByRefObject _myMarshalByRefObject;
public MyProxy(Type myType, string uri)
: base(myType)
{
_myMarshalByRefObject = (MarshalByRefObject)RemotingServices.Connect(myType, uri, null);
_uri = uri;
}

public override IMessage Invoke(IMessage myIMessage)
{
RealProxy rp = RemotingServices.GetRealProxy(_myMarshalByRefObject);
IMessage retMsg = rp.Invoke(myIMessage);

if (retMsg is IMethodReturnMessage)
{
IMethodReturnMessage mrm = (IMethodReturnMessage)retMsg;
String s= (String)CallContext.GetData("User");
if (s == null)
Console.WriteLine("Empty!");
else
Console.WriteLine("Not Empty");
}
return retMsg;
}
}


в теле метода делается СетДата("Юзер", "ИмяЮзер")

Как бы теперь объединть твой код, где работает передача контекста,
с кодом Маклина, где работает серверная часть?
ava
Shit_happenes | 17.08.2007, 15:53 #
У тебя твой пример реально при вызове метода Hello() пишет в консоле сервера "Hello Begin!"?
У меня "Hello Begin!" выводится в клиентской консоли.

Как сделать чтобы "Hello Begin!" выводил на сервере?
ava
tol05 | 17.08.2007, 19:36 #
Значит так. То, что я написал - это булшит. Пример, взятый мной с Real Proxy class и притянутый за уши к нашему примеру...

Почитал Ingo Rammer-а
Новый прокси
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class ProxyTest :RealProxy
{
String myURIString;
IMessageSink _sinkChain;

public ProxyTest(Type type, string uri) : base(type)
{
myURIString = uri;
IChannel[] registeredChannels = ChannelServices.RegisteredChannels;
foreach(IChannel channel in registeredChannels)
{
if(channel is IChannelSender)
{
IChannelSender channelSender = (IChannelSender)channel;
_sinkChain = channelSender.CreateMessageSink(myURIString, null, out myURIString);
if(_sinkChain != null) break;
}
}

if(_sinkChain == null)
{
throw new Exception("No channel has been found for " + myURIString);
}
}

public override IMessage Invoke(IMessage msg)
{
Console.WriteLine("MyProxy.Invoke Start");
Console.WriteLine("");
msg.Properties["__Uri"] = myURIString;

LogicalCallContextData data = new LogicalCallContextData("wow!");
CallContext.SetData("data", data);


IMessage retMsg = _sinkChain.SyncProcessMessage(msg);

Console.WriteLine("MyProxy.Invoke - Finish");
return retMsg;
}
}

клиент

class Client
{
static void Main(string[] args)
{
TcpChannel tcp = new TcpChannel();
ChannelServices.RegisterChannel(tcp, false);

ProxyTest pt = new ProxyTest(typeof(Foo), "tcp://localhost:10008/Foo");
Foo foo = (Foo)pt.GetTransparentProxy();

Console.WriteLine(foo.Connect());
Console.WriteLine(foo.Hello());
Console.ReadKey();
}
}

удаленный объект

public interface IFoo
{
string Hello();
string Connect();
}

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class Foo :MarshalByRefObject, IFoo
{
public string Hello()
{
LogicalCallContextData ccData = CallContext.GetData("data") as LogicalCallContextData;
string data = ccData.Data;

Console.WriteLine("Hello Begin! " + data);
return "Hello! " + data;
}

public string Connect()
{
LogicalCallContextData ccData = CallContext.GetData("data") as LogicalCallContextData;
string data = ccData.Data;

return "Connect! " + data;

}

public override Object InitializeLifetimeService ()
{
return null;
}
}

[Serializable]
public class LogicalCallContextData :ILogicalThreadAffinative
{
string data;

public string Data
{
get
{
return data;
}
}

public LogicalCallContextData(string data)
{
this.data = data;
}
}
ava
Shit_happenes | 18.08.2007, 00:20 #
Представляешь, я этот код пробовал пару дней назад,
но вот только вместо SetData() упорно навесился на SetHeaders();
А он как-то специфически работает.

Черт его знает почему использовал SetHeader, ведь в книги Маклина четко сказано,
что данные добавленные при помощи SetData() передаются в
заголовке SOAP(binary) сообщения, а не в теле. Т.е. наверняка данные SetData() пройдут.

Пример не пробовал, сейчас жаль под рукой дотНета нету.
Задачка уж больно интересная, хотелось бы её побыстрее решить.
Как только пример заюзаю, дам знать.

Кстати, если есть время попробуй в этом примере вместо SetData, SeHeader использовать.
Почувствуешь разницу. Хотя уже разок сказалась разница между этими методами. smile
ava
Shit_happenes | 20.08.2007, 09:49 #
Здорово!!! Наконец-то заработало.

Спасибо за помощь.
ava
Shit_happenes | 21.08.2007, 12:32 #
Вот тут ещё один вопросик.
Это всё делается для того, чтобы клиент мог заходить на MS SQL.
Должна при старте появляться формочка подобная MS Sql, либо ВинАутентификацией, либо Ввести пароль и юзера.

С юзером и паролем разобрались, а вот с ВинАутентификацией проблемки появились.

http://community.bartdesmet.net/blogs/bart...08/26/4277.aspx
Сделал подобно этой статье.

WindowsIdentity identity = Thread.CurrentPrincipal.Identity as WindowsIdentity;
if (identity != null && identity.IsAuthenticated)
{
Console.WriteLine("{0} is authenticated on {1}", identity.Name, WindowsIdentity.GetCurrent().Name);
}
else
return null;
using (WindowsImpersonationContext ctx = identity.Impersonate())
{
//Here we are impersonating as the management client user
Console.WriteLine(WindowsIdentity.GetCurrent().Name);
SqlConnection sqlConn = new
SqlConnection("Data Source=user\\sqlexpress;Trusted_Connection=yes;Database=db");
sqlConn.Open();
SqlTransaction sqlTrans = sqlConn.BeginTransaction();
SqlCommand sqlComm = sqlConn.CreateCommand();
sqlComm.Transaction = sqlTrans;
sqlComm.CommandText = "select system_user";
object o = sqlComm.ExecuteScalar();
sqlTrans.Commit();
sqlConn.Close();
return o.ToString();
}


Выкидывает ислючение на SqlConnection sqlConn = new SqlConnection("Data Source=user\\sqlexpress;Trusted_Connection=yes;Database=db");

Без identity.Impersonate() код работает только с аутентификацией сервера.
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
advanced
Submit