Kamil Kliczbor @ asptip.net

31May/090

Dynamiczne wczytywanie Assembly i błąd "Could not load file or assembly"

Scenariusz tym razem wygląda następująco:
w solucji projekty: IDAL - interfejsy dla DAL, DaoFactory - wzorzec fabryki abstrakcyjnej dla całego DAL oraz Model - klasy modelowe, a także Tests - projekt testów jednostkowych.
Z poziomu projektu testów zostały dodane referencje do wszystkich niezbędnych projektów. Dllki znajdują się w katalogu bin/debug. Test:

[TestMethod]

public void CanSaveTag() {

   ITagDao tagDao = ChPortalFactory.CreateTagDao();

   Tag tag = new Tag { Name = "Testowy"};

   bool result = tagDao.Add(tag, 2);

   Assert.IsTrue(result);

}

wyrzuca wyjątek System.IO.FileNotFoundException: Could not load file or assembly (ChPortal.Model).

Klasa fabryka abstrakcyjnej wczytuje dynamicznie Assembly:

public static ITagDao CreateTagDao() {

   string className = DBConnectionString.WebDAL + ".TagDao";

   return (ITagDao)Assembly.Load(DBConnectionString.WebDAL).CreateInstance(className);

}

Pierwsze poszukiwania zacząłem od tego, czy na pewno dllki znajdują się w katalogu testów, potem zacząłem debugować test. Okazało się, że wszystko gra do momentu tworzenia instancji klasy TagDao. No ale co to miało wspólnego w klasą modelową? Otóż, jeżeli klasa TagDao odwołuje się do innego assembly, to również to assembly musi zostać dynamicznie załadowane.
Najpierw zacząłem szukać w necie i znalazłem dosyć duży wpis na blogu, który znajduje się pod tym adresem.
Ale co bardziej ciekawe, to właśnie narzędzie Assembly Binding Log Viewer (Fuslogvw.exe) umożliwiło mi znalezienie błędu.

Ech.. okazało się, że niepotrzebnie dodałem [assembly: AssemblyCulture("pl-PL")], więc Activator poszukiwał tego assembly w katalogu bin/debug/pl-PL.

30May/090

Zgubione hasło sa SQL Server 2008

Rozpatrzmy następujący pesymistyczny scenariusz:
1. Zapomnieliśmy hasła super admina do SQL Servera.
2. Nasze konto administratora lokalnego nie zostało dodane do Loginów w Security dla SQL-a.

Wypadałoby już tylko zrobić reinstall instancji SQL-a. Ale nie trzeba, w pomocy przychodzi magiczne zaklęcie uruchamiające instację bazy w stanie "single user mode".
Opis całej operacji znajduje się tutaj.
Należałoby pamiętać, aby zezwolić użytkownikowi na logowanie.
Dodatkowo opis jak zmienić hasło samego sa.

Filed under: MS SQL Server No Comments
23May/090

Bindowanie kontrolki DropDownList

Ostatnio, w sumie bezmyślnie, bindowałem listę przy użyciu obiektów ListItem w pętli. Jednak po krótkim zastanowieniu pomyślałem sobie, że jednak mając jakąś kolekcję generyczną, można by elegancko użyć właściwości: DataSource, DataValueField, oraz DataValueText.
Postanowiłem zrobić mały teścik i oto jego rezultaty:

Kod c#:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web.UI.WebControls; 

namespace TestBinding
{
   public partial class _Default : System.Web.UI.Page

   {

      public static List<DTO> _list = new List<DTO>();

      public class DTO

      {

         public string CustomerId { get; set; }
         public string ShipName { get; set; }

      }

 

      private readonly DataTable _dataTable = new DataTable();

 

      protected override void OnPreInit(EventArgs e) {

         base.OnPreInit(e);

 

         if (!IsPostBack) {

 

            using (

               SqlConnection connection =

                  new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ToString())) {

               SqlDataAdapter adapter = new SqlDataAdapter("SELECT [CustomerID], [ShipName] FROM [Orders]", connection);

               connection.Open();

               adapter.Fill(_dataTable);

               connection.Close();

            }

 

            foreach (DataRow row in _dataTable.Rows) {

               _list.Add(new DTO { CustomerId = row.ItemArray[0].ToString(), ShipName = row.ItemArray[1].ToString() });

            }

         }

      }

 

      protected void Page_Load(object sender, EventArgs e) {

         //test 1

         DateTime start;

         DateTime stop;

 

         start = DateTime.Now;

         DropDownList1.DataValueField = "CustomerId";

         DropDownList1.DataTextField = "ShipName";

         DropDownList1.DataSource = _list;

         DropDownList1.DataBind();

         stop = DateTime.Now;

         Label1.Text = (stop - start).Milliseconds.ToString();

 

         start = DateTime.Now;

         foreach (DTO dto in _list) {

            DropDownList2.Items.Add(new ListItem(dto.ShipName, dto.CustomerId));

         }

         stop = DateTime.Now;

         Label2.Text = (stop - start).Milliseconds.ToString();

 

         //test 2 - sql

 

         start = DateTime.Now;

         DropDownList3.DataValueField = "CustomerId";

         DropDownList3.DataTextField = "ShipName";

         DropDownList3.DataSource = _dataTable;

         DropDownList3.DataBind();

         stop = DateTime.Now;

         Label3.Text = (stop - start).Milliseconds.ToString();

 

         start = DateTime.Now;

         foreach (DataRow row in _dataTable.Rows) {

            DropDownList4.Items.Add(new ListItem(row.ItemArray[1].ToString(), row.ItemArray[0].ToString()));

         }

         stop = DateTime.Now;

         Label4.Text = (stop - start).Milliseconds.ToString();

      }
   }
}

Kod asp:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TestBinding._Default" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

   <title>Untitled Page</title>

</head>

<body>

   <form id="form1" runat="server">

   <div>

      Lista generyczna

      <br />

      DataBind() <asp:DropDownList ID="DropDownList1" runat="server">

      </asp:DropDownList>

      <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>

      <br />

      <br />

      ListItem() <asp:DropDownList ID="DropDownList2" runat="server">

      </asp:DropDownList>

      <asp:Label ID="Label2" runat="server" Text="Label"></asp:Label>

      <br />

      <br />

      DataTable

      <br />

      DataBind() <asp:DropDownList ID="DropDownList3" runat="server">

      </asp:DropDownList>

      <asp:Label ID="Label3" runat="server" Text="Label"></asp:Label>

      <br />

      <br />

      ListItem() <asp:DropDownList ID="DropDownList4" runat="server">

      </asp:DropDownList>

      <asp:Label ID="Label4" runat="server" Text="Label"></asp:Label>

      <br />

   </div>

   </form>

</body>

</html>

Dane do bindowania wykorzystałem ze standardowej bazy Northwind, tabela Orders liczyła 830 rekordów.

Jak widać mimo "eleganckiego" podejścia do sprawy, rozwiązanie z DataBind() na liście rozwijanej wypada gorzej pod względem wydajnościowym niż w przypadku populowania listy z użyciem obiektu ListItem.