Updating Campaign Member using Salesforce API and C#

Posted by Ruben Canton on February 2, 2012 at 12:45 pm
categories Web programming

Well, if you check at Salesforce API documentation and follow their tutorial to connect to SF database and request data, everything should be fine. The API its pretty flexible and solid. But, once you get to the update point you may find some problem…

I connected to Salesforce and requested my CampaignMember, loading it into an object called “CampaignMember” (yes, im so original). Then, if I tried to update it using something like:

Salesforce.SaveResult[] saveResults = sf.update(new Salesforce.sObject[] { CampaignMember });

It would not work, since it seems that object has every field filled and would try to update all of them, including the read-only ones. So I would receive a saveResults object with the error message “Unable to create/update fields: CampaignId, HasResponded, LeadId. Please check the security settings of this field and verify that it is read/write for your profile“. And that’s why instead of using the loaded object you need to create a new one, set the value you want to update and update just that field.

Then, not reading properly last message, you may think as I did to create a new object (let’s say uCampaignMember) and set uCampaignMember.HasResponded = true; but unfortunately in my case, that field was read-only again. Ok, now I’m stock. How can I update that now if its read-only??? Luckily after testing here and there I found out you have to update its Status instead, doing something like this:

            if (CampaignMember == null) {
                return false;
            } else {
                Connect();

                try {
                    Salesforce.CampaignMember uCampaignMember = new Salesforce.CampaignMember();
                    uCampaignMember.Id = CampaignMember.Id;
                    uCampaignMember.Status = "Responded";
                    Salesforce.SaveResult[] saveResults = sf.update(new Salesforce.sObject[] { uCampaignMember });
                    if (saveResults[0].success) {
                        return true;
                    } else {
                        return false;
                    }
                }
                catch (Exception ex) {
                    throw (ex);
                }
            }

And that will work. If you want to set the campaign member to “not responded” again, just set Status = “Sent”.

Conclusions

When sending an object to be updated it will try to update all the fields the object has filled using its id for the where clause. So, if you read an object from db, modify some of its properties and use that same object to update it on the db it will try to update every field, including the read-only ones, and that will not work.

To update an object you will need then, to create a new one, fill in only the fields you want to update and send it to be updated. Taking care not to fill any read-only field.

Finally, if you are trying to update a Campaign Member to set that it has responded to an email campaign, instead of updating HasResponded = true, as you may think would be the logic, since HasResponded is read-only you will have to update its status instead, like in the code above.

 

Embedding images in an Email sent by ASP.Net Server

Posted by Ruben Canton on January 11, 2012 at 11:49 am
categories Web programming

If you want to embed your images in an email sent using ASP.Net server instead than using URLs you can use an AlternateView and use the mime standard to embed them:

    using System.Net.Mail;

    protected void SendBTN_Click(object sender, EventArgs e) {

        // Send email using ASP.Net:
        System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage();

        message.From = new System.Net.Mail.MailAddress(Email_From);
        message.To.Add(Email_To);
        message.Bcc.Add(Email_BCC);
        message.Subject = Email_Subject;
        message.IsBodyHtml = true;
        message.AlternateViews.Add(getS4HRegisteredUsersWithoutAnOrderBody_ForEmail(Customer.Name));

        SmtpClient smtp = new SmtpClient("subdom.myserver.com");
        smtp.Send(message);

        // Show some "Email Sent" msg and all that stuff or return ok.
    }

private AlternateView getS4HRegisteredUsersWithoutAnOrderBody_ForEmail(String CustName) {
        StringBuilder body = new StringBuilder();
        body = SkyGuard.MIS.Email.getTemplate("S4HRegisteredUserWithoutOrder.htm");
        body.Replace("[SUBJECT]", Email_Subject);
        body.Replace("[CUSTNAME]", CustName);
        //These keys are set into the image src attribute
        body.Replace("[LOGO_IMGSRC]", "cid:logo"); //Notice that we are adding a cid:id as the image source
        body.Replace("[SUPPORT_PHOTO_IMGSRC]", "cid:avatar");
        body.Replace("[SIGNATURE_IMGSRC]", "cid:signature");

        AlternateView view = AlternateView.CreateAlternateViewFromString(body.ToString(), null, System.Net.Mime.MediaTypeNames.Text.Html);

        //Company Logo
        LinkedResource logo = new LinkedResource(System.Web.HttpContext.Current.Server.MapPath("~/imgs/Emails/Company_logo.png"), System.Net.Mime.MediaTypeNames.Image.Jpeg);
        logo.ContentId = "logo";
        LinkedResource avatar = new LinkedResource(System.Web.HttpContext.Current.Server.MapPath("~/imgs/Emails/Support_Avatar.png"), System.Net.Mime.MediaTypeNames.Image.Jpeg);
        avatar.ContentId = "avatar";
        LinkedResource signature = new LinkedResource(System.Web.HttpContext.Current.Server.MapPath("~/imgs/Emails/Support_Signature.png"), System.Net.Mime.MediaTypeNames.Image.Jpeg);
        signature.ContentId = "signature";

        view.LinkedResources.Add(logo);
        view.LinkedResources.Add(avatar);
        view.LinkedResources.Add(signature);

        return view;
    }
 

Mailto: and its parameters

Posted by Ruben Canton on December 21, 2011 at 1:29 pm
categories Web standards

Mailto is a link “address” we can set to an anchor tag to let the user send an email to someone with just a click. Something like this:

<a href="mailto:someone@someserver.com">Send email</a>

That would show something like this:
Send email

If you click on there, and you have configured in your PC a default email software to handle it, Outlook or the software you are using will open with a blank email with just an address at the “To” field, the one written in the link. You can also configure your browser to open your Gmail/hotmail/whatever account when doing this.

Now, what if you wanted to send that email with a default subject, cc, bcc or including body? Well you can, just adding parameters as if it were an url like this:

<a href="mailto:someone@someserver.com?subject=Default subject&cc=someone@tocopy.com&bcc=hidden@copied.com&body=Lets start saying this">Send email</a>

Which would look like this:
Send email

List of parameters

  • subject: The email subject.
  • cc: List of emails to send a copy.
  • bcc: List of emails to send a hidden copy (rest of recipients will not see it).
  • body: Some text to add as the email body by default. Limited to 255 characters.
 

How can I force a page jump in HTML printing?

Posted by Ruben Canton on December 8, 2011 at 11:40 am
categories Web programming, Web standards

If you would like to decide when the page will break and the next one will be started when your web page is printed you can use three CSS2.0 styles to set this “jump”.

  • page-break-before: Sets the element page break behavoir before the element starts.
  • page-break-inside: Lets you set that the page break behavior has to be avoided inside this element.
  • page-break-after: Sets the element page break behavoir after the element ends.

So, you can for example add this style to a table and the table will start in a new page when the page is printed:

    table.details {page-break-before: always;}

Or you can have an style like this and use it as a page-breaker.

    .page-break {page-break-before: always;}
    <div class="page-break"></div>

Finally, you may want some element to be printed in the same page, making it break to a new page in case it doesn’t fit in the current one:

    table td.nobreaks {page-break-inside: avoid;}

Or you may want to avoid that an element that doesnt fits completely in a page provokes a jump, so you use all the possible space:

    h1 {page-break-before: avoid;}
 

Adding an HTTP Handler to manage Images requests in .Net

Posted by Ruben Canton on September 15, 2011 at 11:32 pm
categories Web programming

This time I found myself in a very interesting challenge. We store user profile and login images in a server folder and users update their images as they need. Sometimes, when you make a release, it is just better to remove everything and paste the new version (just in case some old file remains on there) which, in case you forget, may end with the user images removed. What a problem!

As always, there are different solutions for this, like using SQL Server to store the images, but I decided to use an external folder which the application would have access and edit rights and a virtual path. Saving the images was not a deal, just using a FileStream object and Write method. The problem came when having to send the images to the user on a request.

If they are stored in a virtual path, there isn’t a real path for them in the site, there is no www.mysite.com/imgs/img.jpg, I have a \\imgs\img.jpg instead. So, how could I set an url for that image so the browser can get it?

Well, the solution was to use some virtual path and return the image when the user tried to access it, this can be done with a Module checking each request to the application, with a webservice, with a fake aspx page that returns an image instead than a page or with a handler. I decided to use the handler since it seems the best option for this purpose.

First, I made the handler just creating a new class, made it use the IHttpHandler interface to make it “interfaceable” and then added the rest of the behavior:

public class UserImagesHandler : IHttpHandler
{
	public UserImagesHandler() { }
    public bool IsReusable { get { return false; } }

    public void ProcessRequest(HttpContext context) {
        HttpRequest request = context.Request;
        HttpResponse response = context.Response;
        String file = System.IO.Path.GetFileName(request.Path);

        context.Response.ContentType = "image/" + System.IO.Path.GetExtension(file).Replace(".", "");
        if (request.RawUrl.ToLower().Contains("profile")) {
            response.TransmitFile(MyNameSpace.Config.PATH_IMG_USER_PROFILE + file);
        } else if (request.RawUrl.ToLower().Contains("login")) {
            response.TransmitFile(MyNameSpace.Config.PATH_IMG_USER_LOGIN + file);
        } else {
            response.StatusCode = 404;
            response.Write("Not found.");
        }

    }
}

The method IsReusable comes with the IHttpHandler interface and is used to determine if the handler should be kept in memory and be reused by any request or should make a new instance for every request. In our case our handler should be reusable so it handles every request saving proc time and memory.

Now, I need to say IIS to send these requests to this handler. I can do that using the IIS configuration, but that’s limited to the file extension (you can only make a handler for each file extension, you can still create a new file extension for your handler but.. that wasn’t my idea) or you can set it at the webconfig which gives you more flexibility.

There are two ways for adding this to the webconfig depending on if you are using IIS6 or IIS7, since you may have IIS6 at local and 7 at production or viceversa you may want to use both ways so it will work at any IIS.

First way, in IIS6, it is set under the <system.web> tag:

	<system.web>
		<httpHandlers>
            <add verb="*" path="imgs/users/*/*" type="UserImagesHandler" />
		</httpHandlers>
	</system.web>

Second, for IIS7, under the <system.WebServer> tag:

	<system.webServer>
		<handlers>
            <add verb="*" path="imgs/users/*/*" type="UserImagesHandler" name="UserImagesHandler" />
		</handlers>
	</system.webServer>

Once thats done your handler should work and the requests for the images in the virtual path will be catched and responsed with what we have at the real folder. We can also add other features like access control since this is a full request and we have access to the session, cookies or auth. cookies. We could also add querystrings to resize the responsed images, make any log or any other thing you want to control.

WordPress Themes