Get client IP in Silverlight application.

 

http://www.michaelsnow.com/2010/04/29/silverlight-tip-of-the-day-9-obtaining-your-clients-ip-address/

Bueno, siguiendo los consejos del amigo Michael, decido hacer un WCF. Pero yo me pregunto, con lo facilito que era en ASP.NET, total era una mísera línea del Http.Context. Pero claro, ahora en SL, hay que complicarlo, ellos sabrán el porque, supongo que temas de seguridad, de sandbox, y otras gaitas.

Nada, pues sigo, me pongo con mi WCF, lo creo hago un “rename” del IService1 y el Service1, a IMyService y MyService, creo mis métodos, compilo, referencio mi nuevo webservice en una máquina remota, y peta!

¿Qué pasa? Todo parece correcto. Media horita más tarde, se me ocurre mirar si el refactoring ha hecho el “rename” correctamente. ¡Vaya por dios!, se ha dejado un par de sitios sin cambiar.

Lo cambio a mano y ya puedo referenciar.

Perfecto, lo referencio en una aplicación WF para probar, y como no, nuevo problema.

public string GetCustomerIP()
        {
            string customerIP = System.Web.HttpContext.Current.Request.UserHostAddress;
          
            return customerIP;
        }

El HttpContext.Current es “null”. Vaya, pues vamos a mirar que pasa. Un ratito más y resulta que faltan un par de líneas:

[ServiceBehavior]

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

    public class MyService : IMyService
    {

……

}

y en el web.config

<serviceHostingEnvironment multipleSiteBindingsEnabled=”true” aspNetCompatibilityEnabled=”true”   />

Ale, ya me devuelve la IP. Este Michael se ha dejado una parte importante de configuración.

Bueno, no pasa nada, sigo y referencio ahora el WCF en una web Silverlight. Y como no, otro error. Este más raro que un perro verde.

“This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a …….. etc. etc. etc”

Socorrooooo!!! ¡Pero si iba bien en WF! ¿qué pasa ahora? Nada, otro ratito a navegar por google. Otra vez problemas de seguridad, cómo nos complican los hackers.

La solución parece sencilla, crear en el directorio IIS raíz del WCf, el fichero clientaccesspolicy.xml con el contenido:

<access-policy>
 
    <cross-domain-access>
 
        <policy>
 
            <allow-from http-request-headers=”*”>
 
                <domain uri=”*”/>
 
            </allow-from>
 
            <grant-to>
 
                <resource path=”/” include-subpaths=”true”/>
 
            </grant-to>
 
        </policy>
 
    </cross-domain-access>
 
</access-policy>

Pero nada, el error sigue, y sigue, ¿posible problema con la caché del IIS? Pues nada, lo reinicio. Pero sigue el error.

Gracias a Fiddler, me doy cuenta que no busca en ese directorio. ¿Y si muevo el xml al raiz, en mi caso en C:\inetpub\wwwroot? Noooo. sigue el error. Pero el fichero ya lo coge correctamente!. Último intento, reinicio IIS.

Síííííííííííííííííííííííííííííí!!!!!!!!!!!!!!!

Funciona, mi WCF, referenciado desde SL, me devuelve al fin la IP del cliente.

ServiceReference1.MyServiceClient client = new ServiceReference1.MyServiceClient();
           client.GetCustomerIPCompleted += new EventHandler<ServiceReference1.GetCustomerIPCompletedEventArgs>(client_GetCustomerIPCompleted);
           client.GetCustomerIPAsync();

 

Tras maldecir a los dioses y unas horitas de navegación (por google, que no en barca) se ha solucionado el problema. Pero Michael, en tu próximo blog, explayate un poquito más. De todos modos, gracias.

Ale, ¿véis que fácil es coger la ip del cliente? ¡¡¡No quiero pensar si en la próxima versión lo complicarán un poquito más!!!

Sonrisa Prueba superada!

Anuncios

¿Que versión de MS Word está instalada, ¡SIN mirar el registro!?

En muchas aplicaciones, por distintos motivos, no tenemos acceso al registro.

const string ASSEMBLY2003 = “Microsoft.Office.Interop.Word, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”;
const string ASSEMBLY2007 = “Microsoft.Office.Interop.Word, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”;
const string ASSEMBLY2010 = “Microsoft.Office.Interop.Word, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”;

public static Assembly WordAssemby()
{
try
{
var ass = Assembly.Load(ASSEMBLY2003);

return ass;
}
catch ()
{
return null;
}
}

Por supuesto, esto se puede aplicar a cualquier ensamblado del GAC.

Sonrisa

Refrescar IsBusy de la View mientras cargo un proyecto WF en el ViewModel

 

Me he encontrado con este problema, y tras pegarme con Threads,  BackgroundWorker, Task, Dispatcher, DispatcherPriority, delegados y hasta SynchronizationContext, al final la solución ha sido:

En el View:

public MainWindow()
       {
         
           InitializeComponent();

Messenger.Default.Register<MyMessenger<Busy>>(this, (p) =>
{

// p.Content.Wait es bool
               BusyOn(p.Content.Wait);

});

         

====================

private void BusyOn(bool b)
       {
           Dispatcher.Invoke(DispatcherPriority.Send, (ThreadStart)delegate
           {
              _busy.IsBusy = b;

              _busy.MyRefresh();
              
           });

//NO FUNCIONA   

//_context = SynchronizationContext.Current;
           //if (_context == null)
           //{
           //    _context = new SynchronizationContext();
           //}

       //    _context.Send(new SendOrPostCallback((s) =>
           //        {
           //            _busy.IsBusy = b;
           //            _busy.MyRefresh();
           //        }

           //), null);

 

//NO FUNCIONA

//_busy.Dispatcher.BeginInvoke((Action)(() =>
//{
// _busy.IsBusy = b;

// _busy.MyRefresh();

//}), DispatcherPriority.Send );

       }

==================

public static class DelegateExtensionMethods
    {

        private static Action EmptyDelegate = delegate() { };

 

        public static void MyRefresh(this UIElement uiElement)
        {

            uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);

        }

    }

==============

en el ViewModel:

private void SetBusy(bool b)//object sender, DoWorkEventArgs e)
      {
          var v = new Busy {  Wait =b};
          Messenger.Default.Send(new MyMessenger<Busy >(v));
      }

private void OpenVista()
        {
          
                          
                        var f = new frm ();
                        f.Loading += new frm.LoadHandler(this.SetBusy);
                         f.Show();

             }

======

en el form WF

// add a delegate
       public delegate void LoadHandler(bool loading);

       // add an event of the delegate type
       public event LoadHandler Loading;

 

private void frm_Load(object sender, EventArgs e)
       {
           //indico q empiezo a cargar
           Loading(true);

          //aquí cargo todo

         
           //indico q he terminado de cargar
           Loading(false);
       }

====

un poco rollo, pero el problema es que el Load del WF me congela el shell de WPF y a pesar de enviar mensajes a la vista, no actualiza los elementos de ésta.

Como veréis utilizo Galasoft para enviar mensajes entre View y ViewModel.

Pero al final, prueba superada.

Sonrisa

DialogMessage con MVVM

http://mvvmlight.codeplex.com/discussions/267282

In my ViewModel I have this code:

 var message = new DialogMessage("Dit artikel is al verkocht", DialogMessageCallback)
                {
                    Button = MessageBoxButton.OK,
                    Caption = "Continue?"
                };

                Messenger.Default.Send(message);

And in my MainWindow.xaml.cs:

InitializeComponent(); Messenger.Default.Register<DialogMessage>( this, msg => { var result = MessageBox.Show( msg.Content, msg.Caption, msg.Button); // Send callback msg.ProcessCallback(result); });

 

Como veis, no tiene ninguna complicación gracias a Galasoft.

 

Sonrisa

¿Estamos en modo diseño?

Si necesitas saber si estás en ejecución o diseño, con estas pocas líneas podrás saberlo en tu programa:

/// <summary>
        /// indica si estamos en diseño
        /// </summary>
        /// <returns></returns>
        public static bool IsInDesignMode
        {

            get
            {
               bool returnFlag = false;
#if DEBUG

                if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
                {

                    returnFlag = true;
                }

                else if (Process.GetCurrentProcess().ProcessName.ToUpper().Equals(“DEVENV”))
                {

                    returnFlag = true;
                }
#endif

Bring a form to the front

Desde mi shell WPF hago llamadas a dlls que son los diferentes programas que aún tengo en WF. El problema es que, a veces, el form que cargo, se queda detrás de la ventana WPF.

Si te pasa esto, la solución es muy simple:

private void frm_Shown(object sender, EventArgs e)
       {
          
this.TopMost = true;
           this.Focus();
           this.BringToFront();
           this.TopMost = false;
       }

Para acortar, puedes crear un “form” con este evento, del que heredarán todos los demás.

http://www.techtalkz.com/c-c-sharp/104703-bring-form-front.html

Sonrisa