Tags: | Categories: C# Posted by talgiladi on 10/3/2008 8:47 PM | Comments (5)

החלטתי לכתוב קצת על שירותי רשת, שירותי ווב או בקיצור web services...
אז מכיוון שכולנו יודעים ליצור שירות בסיסי אני אדלג על ההתחלה ואעבור ישירות לשירותים מתקדמים.
כשאני אומר שירותים מתקדמים אני לא מתכוון לקוד מתוחכם שאנחנו יוצרים, אלא לתמיכה מובנית, סטנדרטים חדשים שצומחים לאיטם
שמטרתם להוסיף פיצ'רים חדשים ותמיכה בעוד סוגי שירותים לשירותי הרשת.
לדוגמה -  תמיכה מובנית בהצפנה, חתימה דיגיטלית, טרנזאקציות ועוד...

הבשורה הרעה שכולנו לא אוהבים לשמוע, זה שצריך להוריד משהו מהאינטרנט... כן, זה עדיין לא בא בתור סטנדרט בתוך הפריימוורק, אולי בעתיד...
אז תגשו לגוגל ותחפשו wse, בפעם האחרונה שבדקתי הגירסה הייתה 3.0 ולינק ההורדה ממיקרוסופט הוא כאן
לאחר ההתקנה יהיו לכם כמה דוגמאות קוד והוראות שימוש די נוחות...
הדבר הראשון שצריך לעשות אם אנחנו רוצים להשתמש בחתימה דיגיטלית זה להתקין מפתח אסימטרי.
למזלנו הקובץ מגיע עם 4 מפתחות לצורך הדוגמה, והדבר היחיד שצריך לעשות זה להריץ את הקובץ setup.bat שנמצא בתוך ספריית ההתקנה, בתוך ספריית samples, רק שימו לב שצריך לפתוח את שורת הפקודה של ויזואל סטודיו קודם:

cmd

ללכת לנתיב שציינתי, ואז לכתוב את שם הקובץ להרצה... תתפללו שהכל יעבוד, ואם כן אז יש לכם 4 מפתחות להצפנה מותקנים על ה iis.

אם ממש בא לראות אותן, ניתן להקיש בשורת הפקודה mmc כדי לפתוח את הקונסול, אחר כך להקיש על file->Add/Remove snap in->Add->certificates->Add
ואז תראו שם את כל המפתחות שמותקנות אצלכם על המחשב מהגלישה באינטרנט... אלו שעכשיו התקנו -  אחת מופיע תחת personal , עוד אחת תחת other people ועוד 2 איפשהו שם...

איך עובדת החתימה הדיגיטלית בשירותי רשת?
כמו בכל מקום אחר. הלקוח מייצר מפתח פרטי-ציבורי מהחתימה שלו. את המפתח הציבורי הוא ישלח ביחד עם ההודעה לשרת שמפעיל את שירותי הרשת.
הלקוח עושה האש על ההודעה.
על קוד ההאש שקיבלנו, אנו מבצעים את ההצפנה בעזרת המפתח הפרטי, מה שקיבלנו עכשיו זו בעצם החתימה הדיגיטלית.
את החתימה אנחנו מצרפים להודעה שאנחנו שולחים.

בצד השרת- השרת מקבל את ההודעה ורואה חתימה דיגיטלית מצורפת ב header של ההודעה.
בעזרת המפתח הציבורי שהלקוח צירף, השרת מנסה לפענח את החתימה. אם הצליח אז עכשיו יש בידינו את קוד ההאש של ההודעה.
כעת השרת יעשה בעצמו חישוב האש על ההודעה (כמובן בעזרת אותו אלגוריתם שהלקוח השתמש - הלקוח צריך להעביר גם את הפרט הזה בהודעה...)
ועכשיו נשאר רק להשוות אם ההאש שפיענחנו מהלקוח זהה להאש שביצענו בעצמנו... אם לא, ההודעה שונתה בדרך...

תמיכה נוספת למעין חתימה דיגיטלית היא חתימה על ידי שם משתמש וסיסמא, שהם משמשים בעצם במקום המפתח הפרטי. החיסרון הברור הוא שלשרת צריכים להיות
את שם המשתמש והסיסמא כדי לוודא שאכן החתימה אמיתית...

רק עוד דקה של תיאוריה, דבר שצריך לדעית לפני שמתחילים עם כל השירותים המורחבים האלה, זה שכל התוספות האלה מצורפות ל headers של ההודעה, ה wse יושב ומאזין בשרת ואצל הלקוח, וברגע שהלקוח שולח הודעה, אז לפי ההגדרות ה wse לוקח את ההודעה, עושה מה שצריך איתה, ומעביר אותה הלאה לשרת. בצד השרת שוב ה wse מאזין להודעות המגיעות, מנתח אותן לפי ההגדרות, ואז אם הכל בסדר מעביר את ההודעה לקוד שלנו. כך שאם אתם בדיבאג על השרת, ומשום מה הודעה לא מגיעה לשם, כנראה היא לא עברה את  מחסום ה wse...

אז בואו נתחיל עם חתימה על ידי שם משתמש וסיסמא.

הגדרת צד השרת

  1. קודם כל ניצור אתר פשוט. 
     
    עכשיו כמה הגדרות
    בואו נפתח את כלי הקונפיגורציה שהגיע עם ההתקנה. אם אתם כבר בויזואל סטודיו אז לחצן ימני על הפרוייקט ותראו למטה לחצן בשם wse settings. (אם לא, אז פשוט תתחילו את התוכנה  לבד דרך תפריט ההתחלה:

    openConfiguration

    אבל אז תצטרכו למקם את הקובץ שנוצר לבד בתוך תיקיית האתר שלכם)

    התוכנה הזאת בעצם חוסכת מאיתנו את המשחק בווב קונפיג ומכניסה לשם את ההגדרות הדרושות.
  2. בטאב הראשון נאפשר את השימוש בהרחבות המתקדמות בפרוייקט שלנו:

    enableWSE
  3. בטאב ה security בחלק של seucrity tokens manager נוסיף מנהל חדש על ידי לחיצה על add

    AddToken

    תבחרו בקומבו בוקס Username Token Manager ושאר הפרטים יתמלאו לבד.
    כאן בעצם הגדרנו שההודעה שלנו צריכה להכיל חתימה בעזרת שם משתמש וסיסמה.

  4. אנחנו צריכים לעשות זה ליצור מחלקה שאליה יעביר ה wse את שם המשתמש, והיא תחזיר לו את הסיסמה
    כדי שהוא יוכל לבדוק את החתימה הדיגיטלית. המחלקה הזאת במצב רגיל מן הסתם תמשוך את המידע מדטה בייס או קובץ.
    את שם המחלקה, שעוד מעט נראה איך ליצור, אנו כותבים בתיבת הטקסט Type. אני קראתי למחלקה UserNameTokenHandler

    UserNameTokenHandler

    תקליקו על אישור

  5. עוד דבר יש לנו בטאב הזה, כדי שנוכל לשחק עם המפתחות שלנו, שאינן אמיתיים ולא הונפקו על ידי חברה מורשית כגון verisign וכו',

    יש לסמן צ'ק בוקס בשם Allow test roots
    allowTestRoots


  6. עלינו ליצור קובץ שיכיל את ה Policy. הקובץ הזה מכיל הגדרות שונות לגבי החתימה הדיגיטלית. אתם יכולים להעתיק את הקובץ מספריית הדוגמאות שהגיעה עם התקנה ה wse, שם הקובץ הוא wse3policyCache.config והתוכן שלו הוא

    <policies xmlns="http://schemas.microsoft.com/wse/2005/06/policy">

      <extensions>

        <extension name="usernameForCertificateSecurity" type="Microsoft.Web.Services3.Design.UsernameForCertificateAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

        <extension name="x509" type="Microsoft.Web.Services3.Design.X509TokenProvider, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

        <extension name="requireActionHeader" type="Microsoft.Web.Services3.Design.RequireActionHeaderAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

      </extensions>

      <policy name="ServerPolicy">

        <usernameForCertificateSecurity establishSecurityContext="false" requireSignatureConfirmation="false" messageProtectionOrder="SignBeforeEncrypt" requireDerivedKeys="true" ttlInSeconds="300">

          <serviceToken>

            <x509 storeLocation="LocalMachine" storeName="My" findValue="CN=WSE2QuickStartServer" findType="FindBySubjectDistinguishedName" />

          </serviceToken>

          <protection>

            <request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

            <response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

            <fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />

          </protection>

        </usernameForCertificateSecurity>

        <requireActionHeader />

      </policy>

    </policies>

    פה בעצם אמרנו למנהל המפתחות הכן נימצא המפתח שלי, מה השם שלו ואיך למצוא אותו. הגדרנו גם איך צריכה להיראות בקשה לשרת, התגובה מהשרת והודעות שגיאה.

    7. כעת נראה למנהל ה Policy  היכן ניתן למצוא את הקובץ. לכו לטאב של ה Policy, תסמנו את הצ'ק בוקס כדי לאפשר Policy, תקליקו על Browse ותמצאו את הקובץ הנ"ל.
    כעת תנו שם ל Policy. אצלנו השם הוא ServerPolicy
    AllowPolicy

    תלחצו על אישור
  7. בואו ניצור את המחלקה שתטפל בשם המשתמש:
    ניצור מחלקה בשם UserNameTokenHandler שתירש מהמחלקה UsernameTokenManager. נדרוס את הפונקציה AuthenticateToken שהחתימה שלה היא

    protected override string AuthenticateToken(UsernameToken token)


    הפונקציה הזאת מקבלת מה wse את ה UsernameToken ואמורה להחזיר את הסיסמה עבור המשתמש הזה. עם הסיסמה שאנחנו מחזירים, ה wse מנסה לפענח את החתימה הדיגיטלית, ואם הוא מצליח הוא אז הוא יעשה האש להודעה וישווה לערך שנמצא בחתימה הדיגיטלית. לצורך הדוגמה הקוד יהיה פשוט

     protected override string AuthenticateToken(UsernameToken token)

        {

            if (token.Username == "talg")

            {

                return "mypassword";

            }

            else

            {

                return null;

            }

        }

     

    להורדת הקוד של המחלקה
  8. ניצור ווב סרביס פשוט, ניתן אפילו להשתמש בשלום עולם שנוצר אוטומטי. השינוי היחד שאנחנו צריכים לעשות זה לציין באיזה פוליסי הסרביס הזה ישתמש. אנו יצרנו כבר פוליסי בשם ServerPolicy ובא נשתמש על ידי הוספת המאפיין לפני שם המחלקה של הווב סרביס:

    [Policy("ServerPolicy")]

    וסיימנו את צד השרת... היה ארוך, אבל רוב ההגדרות הן חד פעמיות, וכעת כל סרביס נוסף שתגדירו לא ידרוש שום הגדרה נוספת. אם ה wse יחליט שהבקשה עונה על הדרישות, שבמקרה שלנו הם חתימה דיגיטלית בעזרת שם משתמש וסיסמה, הוא יעביר את הבקשה לסרביס שלנו, אם לא, אנחנו אפילו לא נדע מזה, הודעת שגיאה תיזרק לצד הלקוח...

    להורדת קוד והגדרות השרת

הגדרת צד הלקוח
בצד הלקוח נעשה קצת אחרת, נוריד את ההגדרות מהקופיגורציה ונכניס אותם לקוד, כדי שיקביל לדוגמאות שהגיעו עם ההתקנה.

  1. ניצור פרוייקט, אני יצרתי אפליקציית קונסול.
  2. לחצן ימני על הגדרות פרוייקט-> wse settings
  3. לסמן את הצ'ק בוקס הראשון שמופיע, שבעצם מאפשר שימוש ב wse בפרוייקט הזה:

     enableWSEClient
  4. כעת ניצור הפנייה לווב סרביס בשרת שלנו על ידי הוספת web reference כרגיל. כעת לנקודה הכי חשובה! הפנייה רגילה לווב סרביס יורשת מהמחלקה SoapHttpClientProtocol , אנו צריכים לשנות כך שההפניה שלנו תירש מ WebServicesClientProtocol, שום שינוי אחר לא נדרש בקוד של ההפניה. רק שימו לב שכדאי לכם להוציא את ההפניה מהתיקיה של web references, אחרת כל פעם כשיבוצע עידכון הקוד הישן ימחק ותיצטרכו שוב לשנות את שם המחלקה.
  5. הפנייה בקוד לווב סרביס

    SecureWebService.WebService ws = new WebServiceClient.SecureWebService.WebService();

  6. יצירת מקבילה בקוד לקובץ הפוליסי שיצרנו בשרת:

     UsernameForCertificateAssertion assertion = new UsernameForCertificateAssertion();

  7. נגדיר עם איזו חתימה להשתמש, ואיך למצוא אותה

    assertion.X509TokenProvider = new X509TokenProvider(StoreLocation.CurrentUser,

                                                                    StoreName.AddressBook,

                                                                    "CN=WSE2QuickStartServer",

                                                                    X509FindType.FindBySubjectDistinguishedName);

  8. עוד הגדרה שמופיעה אצלנו בקובץ הפוליסי בשרת:

      assertion.RequireDerivedKeys = true;

  9. כעת נכניס את השם המשתמש והסיסמה:

    assertion.UsernameTokenProvider = new UsernameTokenProvider("talg", "mypassword");

  10. ונוסיף את הפוליסי לווב סרביס:

      Policy policy = new Policy();

                policy.Assertions.Add(assertion);

                ws.SetPolicy(policy);

  11. ונקרא לשירות:

     string result = ws.HelloWorld();

    אם עשינו הכל כמו שצריך, נקבל תשובה, אם לא... אז תיזרק אקספשן...

    להורדת קוד פרוייקט הלקוח
Technorati Tags:

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags: , | Categories: C# Posted by talgiladi on 6/3/2008 7:56 PM | Comments (6)

, לשם כך יש צורך ביצירת אתר חדש או ספריה וירטואלית חדשה (אלא אם כן השתמשתם בקאסיני...)
יוצא לפעמים שאנחנו צריכים להכין תוכנת התקנה של אתר ללקוחות הקוד לא ארוך ומסובך אבל מעצבן קצת.
קודם נוסיף הפניה לשם המתחם using System.DirectoryServices; שמשמש בעצם גם לגישה ל active directory. שימו לב שההפניה צריכה להיות דרך Add Reference :

addreferenceactivedirectory

כעת נפנה ל IIS:

 DirectoryEntry iisRoot = new DirectoryEntry("IIS://" +

                    serverUrl + "/W3SVC/1/Root");

כש serverUrl זו הכתובת של המחשב שעליו מתקינים, במקרה של התקנה אצל הלקוח זה בדרך localhost
כעת, מכיוון שאנחנו רוצים ליצור ספריה וירטואלית ולא ליצור אתר חדש, אנחנו צריכים הפניה לאיזה אתר קיים כבר, אני אפנה לאתר הדיפולטי ושם אצור את הספריה:

 DirectoryEntries defaultSite = iisRoot.Children; ;//default site

כעת ניצור את הספריה החדשה:

 DirectoryEntry newVirtualDirectory =  defaultSite.Add(virtualDirectoryName,iisRoot.SchemaClassName.ToString());//add new site

newVirtualDirectory.CommitChanges();

ו virtualDirectoryName הוא כמובן שם הספריה החדשה

כעת נגיד לו איפה נמצאים הקבצים שהספריה הזאת צריכה להציג

newVirtualDirectory.Properties["Path"].Value = physicalPath;//the path to the files

ו physicalPath זה כמובן הנתיב המלא לתיקיה עם הדפים של האתר החדש שלנו...

כעת קצת מאפיינים לאתר החדש שלנו:

newVirtualDirectory.Properties["AccessRead"][0] = false;

            newVirtualDirectory.Properties["AccessWrite"][0] = true;

            newVirtualDirectory.Invoke("AppCreate", true);

            newVirtualDirectory.Properties["AppFriendlyName"][0] = virtualDirectoryName;

ובסוף לשמור

newVirtualDirectory.CommitChanges();//save the changes

זהו... קליל ביותר, רק קצת קשה לזכירה, אבל גם ככה בקושי משתמשים בקוד הזה אז זה בסדר... פעם אחרת בעזרת השם ניצור אתר חדש ולא ספריה וירטואלית...

עוד משהו קטן, אם אנחנו רוצים לבדוק אם כבר קיימת כזאת ספריה וירטואלית לפני שמנסים ליצור אותה, אז ניתן להשתמש בקוד:

newVirtualDirectory = defaultSite.Find(virtualDirectoryName, oDE.SchemaClassName.ToString());

רק שימו לב שהפונקציה הזאת לא כל כך נחמדה, היא לא מחזירה null אלא זורקת exception אם לא נמצאה הספרייה, אז להקיף ב try catch בבקשה... תיהנו!

להורדת פרוייקט דוגמה

 

Technorati Tags: ,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags: , | Categories: C# Posted by talgiladi on 6/2/2008 9:50 PM | Comments (3)

לעיתים אנו רוצים לשלוט ב WinService על המחשב דרך הקוד. בתוכנה שלנו למשל, מופעלים מספר שירותים על המחשב, ועוד אחד שמפקח עליהם, ועוד יש התקנה של המוצר שצריכה גם להתקין את הסרביסים האלה, ולכן שליטה מוחלטת דרך הקוד הכרחית עבורנו. לשם כך ניעזר במחלקה ServiceController.
קודם כל צריכים להוסיף הפניה לאסמבלי System.ServiceProcess שכן הפניה לשם לא קיימת בברירת המחדל
כעת אפשר להתחיל להשתמש בו

System.ServiceProcess.ServiceController myController = new System.ServiceProcess.ServiceController(svcName);

כפי שניתן לראות הבנאי שלו מקבל את שם הסרביס שאיתו אני רוצה לעבוד - השם הוא כמו שמופיע כשלוחצים alt+ctrl+del ובוחרים את טאב הסרביסים
בינתיים גם אם הסרביס לא קיים הכל עובד כרגיל. ישנה בעיה קטנה - אם פונקציה שעונה לי פשוט האם סרביס קיים או לא, ולכן נתחכם קצת :

if (myController != null)
{
try
{
string s=myController.DisplayName;
myController.Dispose();
return true;
}
catch { return false; }
}
return false;

ניסינו בעצם למשוך מידע ממנו - ואם הסרביס לא קיים אז נקבל טעות ונדע שהוא לא קיים
טוב אז יש לנו סרביס שקיים, כעת אנו רוצים לדעת מה המצב שלו - הוא מותקן בוודאות, אבל אולי הוא התרסק ועצר?

ServiceControllerStatus scs= myController.Status;

אם נרצה לעצור אותו, נשתמש בפונקציה מובנית

switch (myController.Status)
{
case ServiceControllerStatus.Stopped:
//already stopped...nothing to do
break;
case ServiceControllerStatus.StopPending:
myController.WaitForStatus(ServiceControllerStatus.Stopped);
break;
default:
myController.Stop();
myController.WaitForStatus(ServiceControllerStatus.Stopped);
break;
}
myController.Close();

רק נוודא שאנו ממתינים שהוא אכן יעצור...
ולהריץ אותו נשתמש בשיטה זהה:

switch (myController.Status)
{
case ServiceControllerStatus.Stopped:
myController.Start();
myController.WaitForStatus(ServiceControllerStatus.Running);
break;
case ServiceControllerStatus.StopPending:
//wait for it to stop
myController.WaitForStatus(ServiceControllerStatus.Stopped);
//... and then start
myController.Start();
myController.WaitForStatus(ServiceControllerStatus.Running);
break;
case ServiceControllerStatus.StartPending:
//nothing to do...just wait
myController.WaitForStatus(ServiceControllerStatus.Running);
break;
case ServiceControllerStatus.Running:
//nothing to do.already running...
break;
default:
myController.Start();
myController.WaitForStatus(ServiceControllerStatus.Running);
break;
}

כפי שניתן לראות השימוש די אינטואיטיבי, אנו בודקים את מצבו כרגע, לפי זה מחליטים מה לעשות, ובסוף ממתינים שאכן השינוי יתבצע

עכשיו, כדי להתקין ולהסיר סרביסים דרך הקוד, כבר נצטרך שימוש בקוד c++, אבל לא הרבה... להתקנת שירות נגדיר קצת קבועים:

int SC_MANAGER_CREATE_SERVICE = 0x0002;
int SERVICE_WIN32_OWN_PROCESS = 0x00000010;
//int SERVICE_DEMAND_START = 0x00000003;
int SERVICE_ERROR_NORMAL = 0x00000001;
int STANDARD_RIGHTS_REQUIRED = 0xF0000;
int SERVICE_QUERY_CONFIG = 0x0001;
int SERVICE_CHANGE_CONFIG = 0x0002;
int SERVICE_QUERY_STATUS = 0x0004;
int SERVICE_ENUMERATE_DEPENDENTS = 0x0008;
int SERVICE_START = 0x0010;
int SERVICE_STOP = 0x0020;
int SERVICE_PAUSE_CONTINUE = 0x0040;
int SERVICE_INTERROGATE = 0x0080;
int SERVICE_USER_DEFINED_CONTROL = 0x0100;
int SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
SERVICE_QUERY_CONFIG |
SERVICE_CHANGE_CONFIG |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS |
SERVICE_START |
SERVICE_STOP |
SERVICE_PAUSE_CONTINUE |
SERVICE_INTERROGATE |
SERVICE_USER_DEFINED_CONTROL);
int SERVICE_AUTO_START = 0x00000002;

הפונקציה שלנו תקבל 3 משתנים

string svcPath, string svcName, string svcDispName

את הנתיב הפיסי לסרביס שאנו רוצים להתקין, את שם הסרביס ואת השם שבו הוא יוצג
וכעת להתקנה עצמה:

IntPtr sc_handle =NativeMethods.OpenSCManager(null,
null, SC_MANAGER_CREATE_SERVICE);
if (sc_handle.ToInt32() != 0)
{
IntPtr sv_handle = CreateService(sc_handle,-->c++ native method svcName, svcDispName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, svcPath, null, 0,
null, null, null);
if (sv_handle.ToInt32() == 0)
{
CloseServiceHandle(sc_handle);-->c++ native method
throw new
ExternalException("Could not create service");
}
}
else
{
throw new
ExternalException("Could not open handle to service manager");
}

כשאנו משתמשים בעצם ב 2 פונקציות מספריית windows
כמובן שצריך להגדיר פונקציות חיצוניות לפני השימוש...:

[DllImport(
"advapi32.dll")]
public static
extern IntPtr OpenSCManager(string lpMachineName,
string lpSCDB, int scParameter);
[DllImport("Advapi32.dll")]
public static
extern IntPtr CreateService(IntPtr SC_HANDLE,
string lpSvcName, string lpDisplayName,
int dwDesiredAccess, int
dwServiceType, int dwStartType, int
dwErrorControl, string lpPathName,
string lpLoadOrderGroup, int
lpdwTagId, string lpDependencies, string lpServiceStartName, string
lpPassword);

ההגדרה DllImport היא ממש לפי המשמעות - אנו מגדירים הפניה ל DLL מקומי, מגדירים איך נראית הפונקציה ואז ניתן לפנות אליה
זה אמור להספיק כדי להתקין את הסרביס...
אם נרצה להסיר אותו השיטה דומה- קודם נעצור אותו בעזרת השיטה שראינו לעיל, אחר כך נקרא לפונקציות חיצוניות כדי להסיר ולמחוק אותו

StopService(svcName);-->out function
int GENERIC_WRITE = 0x40000000;
IntPtr sc_hndl = OpenSCManager(
null, pan class="code_keywords">nunull, GENERIC_WRITE);
-->c++ method
if (sc_hndl.ToInt32() != 0)
{
int DELETE = 0x10000;
IntPtr svc_hndl = OpenService(sc_hndl, svcName,
DELETE);-->c++ method
if (svc_hndl.ToInt32() != 0)
style="color: #a31515" {
int i = DeleteService(svc_hndl);
-->c++ method
if (i != 0)
{
CloseServiceHandle(sc_hndl);-->c++ method
}
else
{
CloseServiceHandle(sc_hndl);-->c++ method
throw new ExternalException("Could not delete service");
}
}
else
throw new
ExternalException("Could not open service");
}
else throw new ExternalException("Could not open handle to service manager");

לא מסובך כל כך... אומנם משעמם להשתמש בפונקציות והגדרות מובנות במערכת ההפעלה, אבל סביר...

להורדת הפרוייקט

חלק מהקוד נלקח מ http://www.thescripts.com/forum/post932461-9.html

Technorati Tags: ,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags: , | Categories: C#, sql Posted by talgiladi on 5/5/2008 9:28 PM | Comments (5)

משום מה השאלה הזאת נשאלת שוב ושוב בפורומים...
לשמור זה די ברור איך, אני יוצר פקודת sql עם פרמטרים, או stored procedure ,ומעביר אליה את הבתים של התמונה, כמובן שהעמודה בדטה בייס צריכה להיות מסוג image/binary.
לדוגמה:

 byte[] imagedata = null;

        //now we can get the image bytes with filestream on local system, or from FileUpload on our web page

        System.Data.SqlClient.SqlConnection con=new System.Data.SqlClient.SqlConnection("myconstring");

        System.Data.SqlClient.SqlCommand com = new System.Data.SqlClient.SqlCommand("insert into images (imagename,imagedata) values (@imagename,@imagedata)", con);

        com.Parameters.Add(new System.Data.SqlClient.SqlParameter("@imagename", "myimage.gif"));

 

        com.Parameters.Add(new System.Data.SqlClient.SqlParameter("@imagedata", imagedata));

        con.Open();

        com.ExecuteNonQuery();

יופי, איך מושכים, כרגיל, פקודת select רגילה כשמה שאנו מקבלים מהעמודה הזאת היא מערך של בתים עם נתוני התמונה.
עכשיו כדי להציג אותה ללקוח יש כמה שיטות. קודם כל ניתן להפוך את מערך הבתים לאובייקט של BitMap

  byte[] b=null;//get bytes from data base... b=(byte[])com.ExecuteScalar("select imagedata from myimages where...)

            MemoryStream ms=new MemoryStream(b);

            System.Drawing.Bitmap bm = new System.Drawing.Bitmap(ms);

או אם יש לי באתר דף שאמור להציג תמונות מדטה בייס לפי איזה פרמטר שהוא מקבל נשתמש ב Response.BinaryWrite כדי לכתוב את מערך הבתים. בדף הרגיל שבו מוצג הטקסט והתמונות נשים כתובת של תמונה עם כתובת של דף אחר, ובדף האחר נשתמש בפונקציה הזאת כדי לשלוח את הבתים בתור תמונה

נניח שיש לי דף PictureGallery.aspx
בתוך הדף אני רוצה להציג תמונות שימשכו מהדטה בייס. אני יוצר דף מיוחד שכל תפקידו הוא למשוך תמונה מהדטה בייס ולשלוח אותה ללקוח, נקרא לו PictureView.aspx
בדף PictureGallery.aspx אני שם לינקים לדף PictureView.aspx בתור כתובת של תמונה:

<img src="PictureView.aspx?imgid=34"/>

וככה מוסיף תמונות כמה שארצה. כעת בדף PictureView.aspx הקוד יראה משהו כמו:

 byte[] b = (byte[])com.ExecuteScalar("select imagedata from myimages where imageid=" + Request.Params["imgid"]);

 

        Response.ContentType = "image/jpeg";

        Response.BinaryWrite(b);

        Response.End();

Technorati Tags: ,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5